package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.resolver.ConstraintClauses;
import org.junit.jupiter.api.Test;

import java.util.Map;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;

class CarrierConstraintSupportTest {

    @Test
    void stripNonMachineClausesRemovesPayloadEquals() {
        String stripped = CarrierConstraintSupport.stripNonMachineClauses(
                "\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"");
        assertThat(stripped).isEqualToIgnoringWhitespace("true && true");
    }

    @Test
    void stripNonMachineClausesRemovesObjectsEqualsCarrier() {
        String stripped = CarrierConstraintSupport.stripNonMachineClauses(
                "Objects.equals(\"PAY\", message) && Objects.equals(\"ORDER\", machineType)");
        assertThat(stripped).contains("machineType");
        assertThat(stripped).doesNotContain("message");
        assertThat(stripped).contains("true");
    }

    @Test
    void stripNonMachineClausesKeepsMachineDomainClauses() {
        String stripped = CarrierConstraintSupport.stripNonMachineClauses(
                "\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\"");
        assertThat(stripped).contains("machineType");
        assertThat(stripped).doesNotContain("message == ");
        assertThat(stripped).contains("true");
    }

    @Test
    void stripMixedLeavesOnlyDomainClauseMeaningfully() {
        String stripped = CarrierConstraintSupport.stripNonMachineClauses(
                "\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\"");
        assertThat(ConstraintClauses.primaryIdent(
                ConstraintClauses.splitAndClauses(stripped).get(0)))
                .isEqualTo("machineType");
    }

    @Test
    void contradictsWhenCarrierBindingConflictsWithConstraint() {
        assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
                "message == \"SHIP\"",
                Map.of("message", "PAY"))).isTrue();
    }

    @Test
    void doesNotContradictWhenCarrierBindingMatchesConstraint() {
        assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
                "\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"",
                Map.of("message", "PAY"))).isFalse();
    }

    @Test
    void doesNotContradictWhenConstraintLocalsDoNotOverlapCarrierBindings() {
        assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
                "command == ORDER_PAY",
                Map.of("commandKey", "order.pay"))).isFalse();
    }

    @Test
    void carrierOnlyConstraintIgnoresMachineDomainNegations() {
        String constraint = "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"SUBMIT\".equalsIgnoreCase(event) "
                + "&& !(\"ORDER\".equalsIgnoreCase(machineType))";
        assertThat(CarrierConstraintSupport.carrierOnlyConstraint(constraint, Set.of("event")))
                .isEqualTo("\"SUBMIT\".equalsIgnoreCase(event)");
    }

    @Test
    void dispatcherDocumentBranchDoesNotContradictEventBinding() {
        String constraint = "\"DOCUMENT\".equalsIgnoreCase(machineType) && \"SUBMIT\".equalsIgnoreCase(event) "
                + "&& !(\"ORDER\".equalsIgnoreCase(machineType)) && \"DOCUMENT\".equalsIgnoreCase(machineType)";
        assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
                constraint, Map.of("event", "SUBMIT", "eventString", "event", "machineType", "DOCUMENT")))
                .isFalse();
    }

    @Test
    void dispatcherOrderBranchDoesNotContradictEventBinding() {
        String constraint = "\"ORDER\".equalsIgnoreCase(machineType) && \"PAY\".equalsIgnoreCase(event) "
                + "&& \"ORDER\".equalsIgnoreCase(machineType)";
        assertThat(CarrierConstraintSupport.contradictsCarrierBindings(
                constraint, Map.of("event", "PAY", "eventString", "event", "machineType", "ORDER")))
                .isFalse();
    }
}
