package click.kamil.springstatemachineexporter.analysis.resolver;

import org.junit.jupiter.api.Test;

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

class BooleanConstraintEvaluatorTest {

    @Test
    void shouldEvaluateLiteralEqualsAgainstMachineDomain() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"ORDER\".equals(domain)", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"PAYMENT\".equals(domain)", "OrderStateMachineConfiguration")).isFalse();
    }

    @Test
    void shouldEvaluateReverseEqualsAndInequality() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "domain.equals(\"ORDER\")", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "domain != \"ORDER\"", "OrderStateMachineConfiguration")).isFalse();
    }

    @Test
    void shouldEvaluateStringEqualsForKnownLiterals() {
        assertThat(BooleanConstraintEvaluator.evaluateStringEquals("ORDER", "order", true)).isTrue();
        assertThat(BooleanConstraintEvaluator.evaluateStringEquals("ORDER", "order", false)).isFalse();
        assertThat(BooleanConstraintEvaluator.evaluateStringEquals(null, "ORDER", true)).isNull();
    }

    @Test
    void shouldEvaluateCombinedBooleanLogic() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"ORDER\".equals(type) && \"ORDER\".equals(domain)", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"ORDER\".equals(type) && \"PAYMENT\".equals(domain)", "OrderStateMachineConfiguration")).isFalse();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"PAYMENT\".equals(type) || \"ORDER\".equals(type)", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"PAYMENT\".equals(type) || \"DOCUMENT\".equals(type)", "OrderStateMachineConfiguration")).isFalse();
    }

    @Test
    void shouldEvaluateEqualsIgnoreCaseAgainstMachineDomain() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"order\".equalsIgnoreCase(type)", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"payment\".equalsIgnoreCase(type)", "OrderStateMachineConfiguration")).isFalse();
    }

    @Test
    void shouldEvaluateNegatedDomainChecks() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "!(\"PAYMENT\".equals(type))", "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "!(\"ORDER\".equals(type))", "OrderStateMachineConfiguration")).isFalse();
    }

    @Test
    void shouldIgnoreCarrierClausesWhenMatchingMachineDomain() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"ORDER\".equalsIgnoreCase(machineType) && message == \"PAY\"",
                "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"PAYMENT\".equalsIgnoreCase(machineType) && message == \"PAY\"",
                "OrderStateMachineConfiguration")).isFalse();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "\"PAY\".equalsIgnoreCase(message) && message == \"PAY\"",
                "OrderStateMachineConfiguration")).isTrue();
    }

    @Test
    void shouldEvaluateObjectsEqualsAgainstMachineDomain() {
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "Objects.equals(\"ORDER\", machineType)",
                "OrderStateMachineConfiguration")).isTrue();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "Objects.equals(machineType, \"PAYMENT\")",
                "OrderStateMachineConfiguration")).isFalse();
        assertThat(BooleanConstraintEvaluator.isCompatibleWithMachineDomain(
                "Objects.equals(\"ORDER\", machineType) && Objects.equals(\"PAY\", message)",
                "OrderStateMachineConfiguration")).isTrue();
    }

    @Test
    void evaluateBooleanExpressionShouldHandleLogicalOperators() {
        assertThat(BooleanConstraintEvaluator.evaluateBooleanExpression("true && false")).isFalse();
        assertThat(BooleanConstraintEvaluator.evaluateBooleanExpression("true || false")).isTrue();
        assertThat(BooleanConstraintEvaluator.evaluateBooleanExpression("!(false)")).isTrue();
    }
}
