package com.iqser.red.service.peristence.v1.server.integration.tests;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;

import com.iqser.red.service.peristence.v1.server.integration.client.RulesClient;
import com.iqser.red.service.peristence.v1.server.integration.client.VersionClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequestModel;
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxDeprecatedWarnings;
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxErrorMessage;
import com.iqser.red.service.redaction.v1.model.DroolsValidation;
import com.iqser.red.service.redaction.v1.model.RuleValidationModel;

import feign.FeignException;

public class RulesTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private RulesClient rulesClient;

    @Autowired
    private VersionClient versionClient;


    @Test
    public void testRules() {

        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        var response = rulesClient.upload(new RulesUploadRequestModel("lorem ipsum", dossierTemplate.getId(), RuleFileType.ENTITY, false));
        assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.SC_OK);
        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(3); //1. beim Anlegen des DossierTemplates; 2. bei provideTestTemplate(), damit es ACTIVE ist
        assertThat(rulesClient.download(dossierTemplate.getId()).getRules()).isEqualTo("lorem ipsum");

        response = rulesClient.upload(new RulesUploadRequestModel("lorem ipsum dolor sit amet", dossierTemplate.getId(), RuleFileType.ENTITY, false));
        assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.SC_OK);
        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(4);
        assertThat(rulesClient.download(dossierTemplate.getId()).getRules()).isEqualTo("lorem ipsum dolor sit amet");

    }


    @Test
    public void testRulesWithRunDrySetTrue() {

        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        List<DroolsSyntaxDeprecatedWarnings> warningMessages = new ArrayList<>();
        warningMessages.add(DroolsSyntaxDeprecatedWarnings.builder().line(1).column(0).message("this function is deprecated").build());
        List<DroolsSyntaxErrorMessage> errorMessages = new ArrayList<>();
        errorMessages.add(DroolsSyntaxErrorMessage.builder().line(1).column(0).message("error message").build());
        var request = new RulesUploadRequestModel("lorem ipsum", dossierTemplate.getId(), RuleFileType.ENTITY, true);
        // case 1: dry-run true, no error messages just warning messages
        when(redactionClient.testRules(new RuleValidationModel(request.getRuleFileType().name(), request.getRules()))).thenReturn(DroolsValidation.builder()
                                                                                                                                          .syntaxErrorMessages(Collections.emptyList())
                                                                                                                                          .deprecatedWarnings(
                                                                                                                                                  warningMessages)
                                                                                                                                          .build());

        ResponseEntity<DroolsValidationResponse> response = rulesClient.upload(request);
        assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.SC_OK);
        Objects.requireNonNull(response.getBody());
        assertThat(response.getBody().getSyntaxErrorMessages()).isEmpty();
        assertThat(response.getBody().getDeprecatedWarnings()).isNotEmpty();

        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(2); //1. beim Anlegen des DossierTemplates; 2. bei provideTestTemplate()

        // case 2: dry-run true, error messages and warning messages
        when(redactionClient.testRules(new RuleValidationModel(request.getRuleFileType().name(), request.getRules()))).thenReturn(DroolsValidation.builder()
                                                                                                                                          .syntaxErrorMessages(errorMessages)
                                                                                                                                          .deprecatedWarnings(
                                                                                                                                                  warningMessages)
                                                                                                                                          .build());

        response = rulesClient.upload(request);
        assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.SC_OK);
        Objects.requireNonNull(response.getBody());
        assertThat(response.getBody().getDeprecatedWarnings()).isNotEmpty();
        assertThat(response.getBody().getSyntaxErrorMessages()).isNotEmpty();

        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(2); //1. beim Anlegen des DossierTemplates; 2. bei provideTestTemplate()

    }


    @Test
    public void testRulesWithRunDrySetFalse() {

        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        List<DroolsSyntaxDeprecatedWarnings> warningMessages = new ArrayList<>();
        warningMessages.add(DroolsSyntaxDeprecatedWarnings.builder().line(1).column(0).message("this function is deprecated").build());
        List<DroolsSyntaxErrorMessage> errorMessages = new ArrayList<>();
        errorMessages.add(DroolsSyntaxErrorMessage.builder().line(1).column(0).message("error message").build());
        var request = new RulesUploadRequestModel("lorem ipsum", dossierTemplate.getId(), RuleFileType.ENTITY, false);
        // case 1: dry-run false, error messages and warning messages
        when(redactionClient.testRules(new RuleValidationModel(request.getRuleFileType().name(), request.getRules()))).thenReturn(DroolsValidation.builder()
                                                                                                                                          .syntaxErrorMessages(errorMessages)
                                                                                                                                          .deprecatedWarnings(
                                                                                                                                                  warningMessages)
                                                                                                                                          .build());
        try {
            rulesClient.upload(request);
        } catch (FeignException e) {
            assertThat(e.status()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
        }

        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(2); //1. beim Anlegen des DossierTemplates; 2. bei provideTestTemplate()

        // case 2: dry-run false, no error messages just warning messages
        when(redactionClient.testRules(new RuleValidationModel(request.getRuleFileType().name(), request.getRules()))).thenReturn(DroolsValidation.builder()
                                                                                                                                          .syntaxErrorMessages(Collections.emptyList())
                                                                                                                                          .deprecatedWarnings(
                                                                                                                                                  warningMessages)
                                                                                                                                          .build());

        ResponseEntity<DroolsValidationResponse> response = rulesClient.upload(request);
        assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.SC_OK);
        Objects.requireNonNull(response.getBody());
        assertThat(response.getBody().getDeprecatedWarnings()).isNotEmpty();
        assertThat(response.getBody().getSyntaxErrorMessages()).isEmpty();

        assertThat(versionClient.getVersions(List.of(dossierTemplate.getId()))
                           .get(dossierTemplate.getId()).getRulesVersion()).isEqualTo(3); //1. beim Anlegen des DossierTemplates; 2. bei provideTestTemplate()
    }

}
