package com.customer.work.model.test;

import com.customer.work.model.EmailDto;
import com.customer.work.model.FlowableModelTest;
import com.customer.work.model.FlowableModelTestUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.assertj.core.api.Assertions;
import org.flowable.cmmn.api.runtime.CaseInstance;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

@FlowableModelTest
public class ModelTest {

    @Autowired
    protected FlowableModelTestUtils flowableModelTest;

    @Test
    @Disabled
    public void exportApp() {
        flowableModelTest.exportApp("http://localhost:8093", "TST_APP", "admin", "test");
    }

    @Test
    public void c001Test() {
        flowableModelTest.setTestAuthenticatedUser("admin", null);
        CaseInstance caseInstance = flowableModelTest.startCaseInstance("TST_C001", Map.of());
        String caseInstanceId = caseInstance.getId();
        flowableModelTest.completeOpenTask("TST_P001_T001", flowableModelTest.loadObjectNodeFromResources("model/test/C001/T001.json"), "COMPLETE");
        Assertions.assertThat(flowableModelTest.getRuntimeCasePayload(caseInstanceId).get("testText")).isEqualTo("my test text");

        flowableModelTest.completeOpenTask("TST_C001_T002", flowableModelTest.emptyNode(), "COMPLETE");
        Assertions.assertThat(flowableModelTest.getHistoryCasePayload(caseInstanceId).get("testText")).isEqualTo("my test text");

    }

    @Test
    public void p005HappyPathTest() {
        ObjectNode processIds = flowableModelTest.createRootTestProcessInstance("TST_P005", flowableModelTest.emptyMap());
        flowableModelTest.claimOpenTask("TST_P005_T001", "admin");
        flowableModelTest.completeOpenTask("TST_P005_T001", flowableModelTest.loadObjectNodeFromResources("model/test/P005/T001.json"), null);
        Map<String, Object> rootProcessPayload = flowableModelTest.getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText());
        Assertions.assertThat(rootProcessPayload.get("dataEntry")).isEqualTo("my root text");
    }

    @NotNull
    private Stream<Arguments> p001TestData() {
        return Stream.of(
                Arguments.of("admin", "model/test/P001/initiator.json")
        );
    }
    @ParameterizedTest
    @MethodSource("p001TestData")
    public void p001Test(String initiator, String path) {
        flowableModelTest.setTestAuthenticatedUser(initiator, null);
        ObjectNode processIds = flowableModelTest.createRootTestProcessInstance("TST_P001",
                flowableModelTest.loadMapFromResources(path));
        flowableModelTest.completeOpenTask("TST_P001_T001", flowableModelTest.emptyNode(), "complete");
        Map<String, Object> rootProcessPayload = flowableModelTest.getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText());

        Assertions.assertThat(rootProcessPayload.get("rootResult")).isEqualTo(null);
    }

    @NotNull
    private Stream<Arguments> p002TestData() {
        return Stream.of(
                Arguments.of("model/test/P002/boolean1.json", true, false),
                Arguments.of("model/test/P002/boolean2.json", false, true),
                Arguments.of("model/test/P002/string1.json", "hello root", "hello"),
                Arguments.of("model/test/P002/string2.json", "123", "456"),
                Arguments.of("model/test/P002/string3.json", "123.456,", "456.789"),
                Arguments.of("model/test/P002/int.json", 123, 456),
                Arguments.of("model/test/P002/double.json", 123.456, 456.789),
                Arguments.of("model/test/P002/date.json", "2025-11-12", "2025-11-11")
        );
    }
    @ParameterizedTest
    @MethodSource("p002TestData")
    public void p002Test(String path, Object result, Object out) {
        ObjectNode processIds = flowableModelTest.createRootTestProcessInstance("TST_P002",
                flowableModelTest.loadMapFromResources(path));
        Map<String, Object> rootProcessPayload = flowableModelTest.getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText());

        List<EmailDto> mail = flowableModelTest.getMailList();
        Assertions.assertThat(mail.size()).isEqualTo(0);

        Assertions.assertThat(rootProcessPayload.get("result")).isEqualTo(result);
        Assertions.assertThat(rootProcessPayload.get("out")).isEqualTo(out);
    }

    private Stream<Arguments> p002ExcelTestData() {
        return flowableModelTest.getJsonArgumentsFromExcel("model/test/P002/p002Test.xlsx");
    }
    @ParameterizedTest
    @MethodSource("p002ExcelTestData")
    public void p002ExcelTest(String path, JsonNode argument) {
        ObjectNode result = flowableModelTest.testJsonExcelRow(path, argument);
    }

    private Stream<Arguments> p002ExcelTestData2() {
        return flowableModelTest.getObjArgumentsFromExcel("model/test/P002/p002Test.xlsx");
    }
    @ParameterizedTest
    @MethodSource("p002ExcelTestData2")
    public void p002ExcelTest2(String path, Map<String, Object> argument) {
        Map<String, Object> result = flowableModelTest.testObjExcelRow(path, argument);
        flowableModelTest.checkAndAssertEmail(result, 1,
                "Email", "Test", "test@flowable.com");
        flowableModelTest.checkAndAndAssertAuditRecord(result, 1,
                "Audit record", "TST_P002 Audit trail entry", "system", null);
    }
}
