package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.resolver.StateMachineTypeResolver;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/** Builds a minimal {@link CodebaseContext} for JSON re-export when sources are available. */
@Slf4j
public final class JsonExportContextFactory {

    private JsonExportContextFactory() {
    }

    /**
     * Returns the nearest ancestor directory that looks like a Gradle/Maven module
     * ({@code build.gradle} or {@code pom.xml}), not the monorepo {@code settings.gradle} root.
     */
    public static Path findProjectRoot(Path start) {
        Path current = start != null ? start.toAbsolutePath().normalize() : null;
        while (current != null) {
            if (Files.exists(current.resolve("build.gradle")) || Files.exists(current.resolve("pom.xml"))) {
                return current;
            }
            current = current.getParent();
        }
        return null;
    }

    /** True when the scanned context actually contains classes referenced by the imported JSON. */
    public static boolean contextContainsAnalysisSources(
            click.kamil.springstatemachineexporter.analysis.model.AnalysisResult result,
            CodebaseContext context) {
        if (context == null || result == null) {
            return false;
        }
        if (result.getName() != null && context.getTypeDeclaration(result.getName()) != null) {
            return true;
        }
        if (result.getMetadata() == null || result.getMetadata().getEntryPoints() == null) {
            return false;
        }
        for (click.kamil.springstatemachineexporter.analysis.model.EntryPoint entryPoint
                : result.getMetadata().getEntryPoints()) {
            if (entryPoint.getClassName() != null
                    && context.getTypeDeclaration(entryPoint.getClassName()) != null) {
                return true;
            }
        }
        return false;
    }

    public static CodebaseContext scanProjectRoot(Path projectRoot, List<String> activeProfiles) throws IOException {
        CodebaseContext context = new CodebaseContext();
        if (activeProfiles != null) {
            context.setActiveProfiles(activeProfiles);
        }
        context.setProjectRoot(projectRoot);
        context.setResolveBindings(true);

        Path mainJava = projectRoot.resolve("src/main/java");
        if (Files.isDirectory(mainJava)) {
            context.setSourcepath(List.of(mainJava.toString()));
            context.scan(projectRoot);
            return context;
        }

        click.kamil.springstatemachineexporter.analysis.resolver.SiblingDependencyResolver siblingResolver =
                new click.kamil.springstatemachineexporter.analysis.resolver.SiblingDependencyResolver();
        var projectGraph = siblingResolver.analyzeProject(projectRoot);
        var scanPaths = projectGraph.resolveScanPaths(projectRoot, false);
        context.scan(scanPaths, java.util.Collections.emptySet());
        return context;
    }

    public static StateMachineTypeResolver.MachineTypes resolveMachineTypes(
            String machineName,
            String embeddedStateTypeFqn,
            String embeddedEventTypeFqn,
            CodebaseContext context) {
        if (context != null && machineName != null) {
            StateMachineTypeResolver.MachineTypes resolved =
                    StateMachineTypeResolver.resolveTypes(machineName, context);
            if (resolved.stateTypeFqn() != null || resolved.eventTypeFqn() != null) {
                return resolved;
            }
        }
        return new StateMachineTypeResolver.MachineTypes(embeddedStateTypeFqn, embeddedEventTypeFqn);
    }

    private static boolean hasPackageQualifiedType(String typeFqn) {
        return typeFqn != null && typeFqn.contains(".");
    }
}
