package click.kamil.springstatemachineexporter.html.command;

import click.kamil.springstatemachineexporter.service.ExportService;
import lombok.RequiredArgsConstructor;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

import java.awt.*;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.Callable;

@Command(
    name = "spring-sm-html-exporter",
    mixinStandardHelpOptions = true,
    version = "1.0.0",
    description = "Generates interactive HTML documentation portals for Spring State Machines.",
    headerHeading = "@|bold,underline Usage:|@%n%n",
    synopsisHeading = "%n",
    descriptionHeading = "%n@|bold,underline Description:|@%n%n",
    parameterListHeading = "%n@|bold,underline Parameters:|@%n",
    optionListHeading = "%n@|bold,underline Options:|@%n",
    header = "Welcome to the @|bold,red Interactive State Machine Explorer|@!%n"
)
@RequiredArgsConstructor
public class HtmlExporterCommand implements Callable<Integer> {

    private final ExportService exportService;

    @CommandLine.Spec
    CommandLine.Model.CommandSpec spec;

    @Option(names = {"-i", "--input"}, description = "Input directory containing the Spring Boot project source code. Optional with -j when JSON already contains machine types and canonical identifiers.")
    private Path inputDir;

    @Option(names = {"-j", "--json"}, description = "Input JSON file containing the state machine definition.")
    private Path jsonFile;

    @Option(names = {"-o", "--output"}, description = "Output directory for the generated portal.", defaultValue = "./out_html")
    private Path outputDir;

    @Option(names = {"-f", "--flows"}, description = "Optional path to a custom flows.json file.")
    private Path flowsFile;

    @Option(names = {"-m", "--machine"}, description = "Filter to only export state machines whose name contains this string.")
    private String machineFilter;

    @Option(names = {"-p", "--profiles"}, description = "Spring profiles to activate for property resolution.", split = ",")
    private List<String> activeProfiles;

    @Option(names = {"--open"}, description = "Automatically open the generated HTML portal in your default browser.")
    private boolean openPortal;

    @Option(names = {"--no-diamonds"}, description = "Disable rendering choice pseudostates as PlantUML diamonds (render them as normal state nodes instead).")
    private boolean noDiamonds;

    @Option(names = {"--no-metadata-pane"}, description = "Disable rendering the left metadata pane (entry points, flows) in the HTML viewer.")
    private boolean noMetadataPane;

    @Option(names = {"--debug"}, description = "Enable diagnostic mode to show unresolved call chains and detailed analysis logging.", defaultValue = "false")
    private boolean debug;

    @Option(names = {"--include-generated-sources"}, description = "Scan existing Maven target/ and Gradle build/ trees for pre-generated .java sources. Does not run Maven or Gradle.", negatable = true, defaultValue = "true", fallbackValue = "true")
    private boolean includeGeneratedSources = true;

    @Option(names = {"--inline-accessors"}, description = "Index trivial JavaBean/record accessors at scan time and inline them during call-chain and constant resolution.", negatable = true, defaultValue = "true", fallbackValue = "true")
    private boolean inlineAccessors = true;

    @Override
    public Integer call() throws Exception {
        var out = spec.commandLine().getOut();
        var err = spec.commandLine().getErr();

        if (debug) {
            System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
            out.println(CommandLine.Help.Ansi.AUTO.string("@|bold,cyan Diagnostic mode enabled|@"));
        }

        if (inputDir == null && jsonFile == null) {
            inputDir = Path.of(".");
        }

        out.println(CommandLine.Help.Ansi.AUTO.string("@|bold,red Initializing Interactive Portal Generation...|@"));
        if (jsonFile != null) {
            out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Input JSON File:|@  " + jsonFile.toAbsolutePath()));
        } else {
            out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Input Directory:|@  " + inputDir.toAbsolutePath()));
        }
        out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Output Directory:|@ " + outputDir.toAbsolutePath()));
        
        try {
            // Force HTML and JSON formats for the interactive portal
            List<String> formats = List.of("html", "json");
            List<String> profiles = activeProfiles != null ? activeProfiles : java.util.Collections.emptyList();
            
            if (noMetadataPane) {
                System.setProperty("html.hideMetadataPane", "true");
            }
            
            if (jsonFile != null) {
                exportService.runJsonExporter(jsonFile, outputDir, formats, profiles, click.kamil.springstatemachineexporter.exporter.EnumFormat.fn, click.kamil.springstatemachineexporter.exporter.EnumFormat.fn, inputDir);
            } else {
                boolean renderChoicesAsDiamonds = !noDiamonds;
                exportService.runExporter(inputDir, outputDir, formats, renderChoicesAsDiamonds, profiles, flowsFile, machineFilter, click.kamil.springstatemachineexporter.exporter.EnumFormat.fn, click.kamil.springstatemachineexporter.exporter.EnumFormat.fn, includeGeneratedSources, inlineAccessors);
            }
            System.clearProperty("html.hideMetadataPane");

            out.println(CommandLine.Help.Ansi.AUTO.string("%n@|bold,green SUCCESS:|@ Interactive documentation generated successfully."));
            
            if (openPortal) {
                out.println(CommandLine.Help.Ansi.AUTO.string("@|cyan Attempting to open portal in browser...|@"));
                openInBrowser(outputDir);
            }
            
            return 0;
        } catch (Exception e) {
            err.println(CommandLine.Help.Ansi.AUTO.string("%n@|bold,red ERROR:|@ Generation failed: " + e.getMessage()));
            e.printStackTrace(err);
            return 1;
        }
    }

    private void openInBrowser(Path outputDir) {
        try {
            // Find the first HTML file in the output dir
            File dir = outputDir.toFile();
            File[] subDirs = dir.listFiles(File::isDirectory);
            if (subDirs != null && subDirs.length > 0) {
                File[] htmlFiles = subDirs[0].listFiles((d, name) -> name.endsWith(".html"));
                if (htmlFiles != null && htmlFiles.length > 0) {
                    Desktop.getDesktop().browse(htmlFiles[0].toURI());
                }
            }
        } catch (Exception e) {
            spec.commandLine().getErr().println("Failed to open browser: " + e.getMessage());
        }
    }
}
