package click.kamil.springstatemachineexporter.analysis.enricher;

import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
import click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata;
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
import click.kamil.springstatemachineexporter.model.Event;
import click.kamil.springstatemachineexporter.model.State;
import click.kamil.springstatemachineexporter.model.Transition;
import org.junit.jupiter.api.Test;

import java.util.List;

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

/**
 * Regression: dispatcher REST chains with {@code external=false}, dynamic trigger event, and empty
 * {@code polymorphicEvents} must still link transitions after package-canonical FQN normalization.
 */
class DispatcherExternalFalseMatchedTransitionsRegressionTest {

    private final TransitionLinkerEnricher enricher = new TransitionLinkerEnricher();

    @Test
    void shouldLinkWhenExternalFalseDynamicTriggerAndPolymorphicEventsWereLost() {
        Transition pay = new Transition();
        pay.setSourceStates(List.of(State.of("OrderState.NEW", "com.example.order.OrderState.NEW")));
        pay.setTargetStates(List.of(State.of("OrderState.PAID", "com.example.order.OrderState.PAID")));
        pay.setEvent(Event.of("OrderEvent.PAY", "com.example.order.OrderEvent.PAY"));

        CallChain chain = CallChain.builder()
                .triggerPoint(TriggerPoint.builder()
                        .event("event")
                        .external(false)
                        .polymorphicEvents(null)
                        .constraint("\"ORDER\".equalsIgnoreCase(machineType)")
                        .build())
                .build();

        AnalysisResult result = AnalysisResult.builder()
                .name("com.example.config.OrderStateMachineConfiguration")
                .stateTypeFqn("com.example.order.OrderState")
                .eventTypeFqn("com.example.order.OrderEvent")
                .transitions(List.of(pay))
                .metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
                .build();

        enricher.enrich(result, null, null);

        assertThat(result.getMetadata().getCallChains().get(0).getMatchedTransitions())
                .hasSize(1)
                .first()
                .extracting("event")
                .isEqualTo("com.example.order.OrderEvent.PAY");
    }

    @Test
    void shouldLinkWhenPolymorphicEventsUseWrongEnumPrefixAfterFqnNormalization() {
        Transition pay = new Transition();
        pay.setSourceStates(List.of(State.of("OrderState.NEW", "com.example.order.OrderState.NEW")));
        pay.setTargetStates(List.of(State.of("OrderState.PAID", "com.example.order.OrderState.PAID")));
        pay.setEvent(Event.of("OrderEvent.PAY", "com.example.order.OrderEvent.PAY"));

        CallChain chain = CallChain.builder()
                .triggerPoint(TriggerPoint.builder()
                        .event("e")
                        .external(false)
                        .polymorphicEvents(List.of("OrderEvents.PAY"))
                        .build())
                .build();

        AnalysisResult result = AnalysisResult.builder()
                .name("com.example.config.OrderStateMachineConfiguration")
                .stateTypeFqn("com.example.order.OrderState")
                .eventTypeFqn("com.example.order.OrderEvent")
                .transitions(List.of(pay))
                .metadata(CodebaseMetadata.builder().callChains(List.of(chain)).build())
                .build();

        new TriggerCanonicalizationEnricher().enrich(result, null, null);
        enricher.enrich(result, null, null);

        assertThat(result.getMetadata().getCallChains().get(0).getMatchedTransitions())
                .hasSize(1)
                .first()
                .extracting("event")
                .isEqualTo("com.example.order.OrderEvent.PAY");
    }
}
