package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.enricher.AnalysisEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.CallChainEnricher;
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
import click.kamil.springstatemachineexporter.analysis.enricher.EntryPointEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.PropertyEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.TriggerCanonicalizationEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.TriggerEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.TransitionLinkerEnricher;
import click.kamil.springstatemachineexporter.analysis.enricher.SemanticCallChainDedup;
import click.kamil.springstatemachineexporter.analysis.enricher.path.ForwardPathEstimationEnricher;
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;

import java.util.List;

public class EnrichmentService {
    private final List<AnalysisEnricher> prePropertyEnrichers;
    private final List<AnalysisEnricher> postPropertyEnrichers;

    /** Single-phase pipeline (all enrichers run together; used by focused tests). */
    public EnrichmentService(List<AnalysisEnricher> enrichers) {
        this(enrichers, List.of());
    }

    public EnrichmentService(
            List<AnalysisEnricher> prePropertyEnrichers,
            List<AnalysisEnricher> postPropertyEnrichers) {
        this.prePropertyEnrichers = prePropertyEnrichers;
        this.postPropertyEnrichers = postPropertyEnrichers;
    }

    public static EnrichmentService createDefault() {
        return new EnrichmentService(
                List.of(
                        new TriggerEnricher(),
                        new EntryPointEnricher(),
                        new PropertyEnricher()),
                List.of(
                        new CallChainEnricher(),
                        new ForwardPathEstimationEnricher(),
                        new TriggerCanonicalizationEnricher(),
                        new TransitionLinkerEnricher()));
    }

    public void enrich(AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
        enrichPreProperty(result, context, intelligence);
        enrichPostProperty(result, context, intelligence);
    }

    public void enrichPreProperty(
            AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
        runEnrichers(prePropertyEnrichers, result, context, intelligence);
    }

    public void enrichPostProperty(
            AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
        runEnrichers(postPropertyEnrichers, result, context, intelligence);
    }

    /** Re-runs transition linking after property resolution without rebuilding call chains. */
    public void relinkAfterPropertyResolution(
            AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
        runEnrichers(
                List.of(new TriggerCanonicalizationEnricher(), new TransitionLinkerEnricher()),
                result,
                context,
                intelligence);
    }

    /**
     * JSON re-export path: when source and entry points are available, rebuild call chains from the
     * call graph so dispatcher triggers regain {@code polymorphicEvents}/{@code external}, then relink.
     */
    public void refreshCallChainsAndRelink(
            AnalysisResult result, CodebaseContext context, CodebaseIntelligenceProvider intelligence) {
        if (result.getMetadata() != null && context != null && intelligence != null) {
            List<CallChain> refreshed = CallChainEnricher.buildCallChainsForMachine(result, context, intelligence);
            if (refreshed != null) {
                List<CallChain> merged = SemanticCallChainDedup.mergeRefresh(
                        result.getMetadata().getCallChains(),
                        refreshed,
                        SemanticCallChainDedup.KeepStrategy.SHORTEST);
                result.setMetadata(click.kamil.springstatemachineexporter.analysis.model.CodebaseMetadata.builder()
                        .triggers(result.getMetadata().getTriggers())
                        .entryPoints(result.getMetadata().getEntryPoints())
                        .callChains(merged)
                        .properties(result.getMetadata().getProperties())
                        .build());
            }
        }
        relinkAfterPropertyResolution(result, context, intelligence);
    }

    private static void runEnrichers(
            List<AnalysisEnricher> enrichers,
            AnalysisResult result,
            CodebaseContext context,
            CodebaseIntelligenceProvider intelligence) {
        for (AnalysisEnricher enricher : enrichers) {
            enricher.enrich(result, context, intelligence);
        }
    }
}
