#!/usr/bin/env npx ts-node
/**
 * @file generate-reference-storybook.ts
 * @description Generates a reference Storybook from @kern-ux/native package.
 *
 * This script:
 * 1. Clones the kern-ux-plain repository (contains the official Storybook)
 * 2. Builds the Storybook static files
 * 3. Copies them to the tests/vrt/reference directory for VRT baseline comparisons
 *
 * This ensures our Drupal SDC components are compared against the official
 * KERN-UX design system implementation.
 */

import { execSync } from "child_process";
import * as fs from "fs";
import * as path from "path";

/** Configuration for the reference Storybook generation */
interface Config {
    /** Temporary directory for cloning the repo */
    tempDir: string;
    /** Git repository URL */
    repoUrl: string;
    /** Branch to use */
    branch: string;
    /** Output directory for the built Storybook */
    outputDir: string;
}

const config: Config = {
    tempDir: path.join(process.cwd(), ".kern-ux-reference"),
    repoUrl: "https://gitlab.opencode.de/kern-ux/kern-ux-plain.git",
    branch: "v2.3.2",
    outputDir: path.join(process.cwd(), "tests", "vrt", "reference-storybook"),
};

/**
 * Logs a message with a prefix
 * @param message - The message to log
 */
function log(message: string): void {
    console.log(`[generate-reference] ${message}`);
}

/**
 * Logs an error message with a prefix
 * @param message - The error message to log
 */
function logError(message: string): void {
    console.error(`[generate-reference] ERROR: ${message}`);
}

/**
 * Executes a shell command and returns the output
 * @param command - The command to execute
 * @param options - Options for execSync
 * @returns The command output as a string
 */
function exec(
    command: string,
    options: { cwd?: string; stdio?: "inherit" | "pipe" } = {}
): string {
    const defaultOptions = {
        encoding: "utf-8" as const,
        stdio: options.stdio ?? ("inherit" as const),
    };
    const result = execSync(command, { ...defaultOptions, cwd: options.cwd });
    return typeof result === "string" ? result : "";
}

/**
 * Cleans up the temporary directory
 */
function cleanup(): void {
    if (fs.existsSync(config.tempDir)) {
        log("Cleaning up temporary directory...");
        fs.rmSync(config.tempDir, { recursive: true, force: true });
    }
}

/**
 * Clones the kern-ux-plain repository
 */
function cloneRepository(): void {
    log(`Cloning ${config.repoUrl}...`);

    // Clean up any existing temp directory
    cleanup();

    // Clone the repository (shallow clone for speed)
    exec(`git clone --depth 1 --branch ${config.branch} ${config.repoUrl} ${config.tempDir}`);

    log("Repository cloned successfully.");
}

/**
 * Installs dependencies in the cloned repository
 */
function installDependencies(): void {
    log("Installing dependencies...");
    exec("npm ci", { cwd: config.tempDir });
    log("Dependencies installed successfully.");
}

/**
 * Builds the Storybook
 */
function buildStorybook(): void {
    log("Building Storybook...");

    // The kern-ux-plain repo uses "npm run build" which builds both CSS and Storybook
    // We only need the Storybook build, but the CSS is required first
    exec("npm run build", { cwd: config.tempDir });

    log("Storybook built successfully.");
}

/**
 * Copies the built Storybook to the output directory
 */
function copyStorybookOutput(): void {
    const storybookBuildDir = path.join(config.tempDir, "storybook-static");

    if (!fs.existsSync(storybookBuildDir)) {
        throw new Error(
            `Storybook build directory not found at ${storybookBuildDir}. ` +
            "The build may have failed or the output directory structure may have changed."
        );
    }

    // Create output directory if it doesn't exist
    if (!fs.existsSync(config.outputDir)) {
        fs.mkdirSync(config.outputDir, { recursive: true });
    } else {
        // Clean existing output
        fs.rmSync(config.outputDir, { recursive: true, force: true });
        fs.mkdirSync(config.outputDir, { recursive: true });
    }

    // Copy the Storybook build
    log(`Copying Storybook to ${config.outputDir}...`);
    fs.cpSync(storybookBuildDir, config.outputDir, { recursive: true });

    log("Storybook copied successfully.");
}

/**
 * Gets the version of @kern-ux/native from the cloned repo
 * @returns The version string
 */
function getKernUxVersion(): string {
    const packageJsonPath = path.join(config.tempDir, "package.json");
    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
    return packageJson.version as string;
}

/**
 * Injects the KERN CSS link into iframe.html for proper styling.
 *
 * The reference Storybook loads CSS dynamically via JavaScript, which causes
 * race conditions during VRT screenshot capture. This fix adds a static CSS
 * link to ensure styles are loaded before screenshots are taken.
 */
function injectCssLink(): void {
    const iframeHtmlPath = path.join(config.outputDir, "iframe.html");

    if (!fs.existsSync(iframeHtmlPath)) {
        logError("iframe.html not found - cannot inject CSS link");
        return;
    }

    log("Injecting KERN CSS link into iframe.html...");

    let content = fs.readFileSync(iframeHtmlPath, "utf-8");

    // Check if CSS is already injected
    if (content.includes('href="/kern.css"')) {
        log("CSS link already present - skipping injection");
        return;
    }

    // Find the fira-sans.css link and add kern.css after it
    const searchPattern = '<link rel="stylesheet" href="/fonts/fira-sans.css" />';
    const replacement = `${searchPattern}\n<link rel="stylesheet" href="/kern.css" />`;

    if (content.includes(searchPattern)) {
        content = content.replace(searchPattern, replacement);
        fs.writeFileSync(iframeHtmlPath, content);
        log("CSS link injected successfully");
    } else {
        logError("Could not find fira-sans.css link - CSS injection may need manual update");
    }
}

/**
 * Fixes the theme handling in iframe.html for proper dark mode support.
 *
 * The reference Storybook hardcodes the theme to "light" on DOMContentLoaded,
 * which overrides the theme passed via URL parameters (globals=theme:dark).
 * This fix replaces that script with one that reads the theme from the URL
 * and applies it correctly.
 */
function fixThemeHandling(): void {
    const iframeHtmlPath = path.join(config.outputDir, "iframe.html");

    if (!fs.existsSync(iframeHtmlPath)) {
        logError("iframe.html not found - cannot fix theme handling");
        return;
    }

    log("Fixing theme handling in iframe.html for dark mode support...");

    let content = fs.readFileSync(iframeHtmlPath, "utf-8");

    // The hardcoded light theme script pattern to replace
    const hardcodedThemeScript = `<script>
  window.addEventListener("DOMContentLoaded", (event) => {
    document.documentElement.setAttribute("data-kern-theme", "light");
    // document.documentElement.setAttribute("data-theme", "light");
  });
</script>`;

    // Dynamic theme script that reads from URL parameters
    const dynamicThemeScript = `<script>
  /**
   * Dynamic theme handler for VRT testing.
   * Reads the theme from Storybook globals URL parameter (globals=theme:light|dark)
   * and applies it to the document for KERN-UX styling.
   */
  window.addEventListener("DOMContentLoaded", (event) => {
    // Parse the URL to get the globals parameter
    const urlParams = new URLSearchParams(window.location.search);
    const globals = urlParams.get("globals") || "";
    
    // Extract theme from globals (format: "theme:light" or "theme:dark")
    let theme = "light"; // Default to light
    const themeMatch = globals.match(/theme:(light|dark)/);
    if (themeMatch) {
      theme = themeMatch[1];
    }
    
    // Apply the theme to the document
    document.documentElement.setAttribute("data-kern-theme", theme);
    
    // Log for debugging
    console.log("[KERN-UX VRT] Applied theme:", theme);
  });
</script>`;

    if (content.includes(hardcodedThemeScript)) {
        content = content.replace(hardcodedThemeScript, dynamicThemeScript);
        fs.writeFileSync(iframeHtmlPath, content);
        log("Theme handling fixed - dark mode now supported via URL parameters");
    } else {
        // Try a more flexible pattern match for variations
        const flexiblePattern = /window\.addEventListener\("DOMContentLoaded",\s*\(event\)\s*=>\s*\{\s*document\.documentElement\.setAttribute\("data-kern-theme",\s*"light"\);[^}]*\}\);/;
        if (flexiblePattern.test(content)) {
            content = content.replace(
                /<script>\s*window\.addEventListener\("DOMContentLoaded",\s*\(event\)\s*=>\s*\{\s*document\.documentElement\.setAttribute\("data-kern-theme",\s*"light"\);[^<]*<\/script>/s,
                dynamicThemeScript
            );
            fs.writeFileSync(iframeHtmlPath, content);
            log("Theme handling fixed (flexible match) - dark mode now supported");
        } else if (content.includes("data-kern-theme") && content.includes("DOMContentLoaded")) {
            logError("Found theme script but pattern didn't match - manual review needed");
            log("Attempting alternative fix...");
            
            // As a fallback, inject our script after the existing one to override it
            const bodyTag = "</body>";
            const overrideScript = `
${dynamicThemeScript}
</body>`;
            if (content.includes(bodyTag)) {
                content = content.replace(bodyTag, overrideScript);
                fs.writeFileSync(iframeHtmlPath, content);
                log("Injected theme override script before </body>");
            }
        } else {
            log("No hardcoded theme script found - theme handling may already be correct");
        }
    }
}

/**
 * Writes metadata about the reference Storybook
 */
function writeMetadata(): void {
    const version = getKernUxVersion();
    const metadata = {
        generatedAt: new Date().toISOString(),
        kernUxVersion: version,
        repository: config.repoUrl,
        branch: config.branch,
    };

    const metadataPath = path.join(config.outputDir, "reference-metadata.json");
    fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

    log(`Reference Storybook metadata written to ${metadataPath}`);
    log(`KERN-UX Version: ${version}`);
}

/**
 * Main function to generate the reference Storybook
 */
async function main(): Promise<void> {
    log("Starting reference Storybook generation...");
    log("This process clones the official kern-ux-plain repository,");
    log("builds its Storybook, and copies it for VRT baseline comparisons.\n");

    try {
        // Step 1: Clone the repository
        cloneRepository();

        // Step 2: Install dependencies
        installDependencies();

        // Step 3: Build Storybook
        buildStorybook();

        // Step 4: Copy output
        copyStorybookOutput();

        // Step 5: Inject CSS fix for VRT
        injectCssLink();

        // Step 6: Fix theme handling for dark mode support
        fixThemeHandling();

        // Step 7: Write metadata
        writeMetadata();

        // Step 8: Cleanup
        cleanup();

        log("\n✓ Reference Storybook generated successfully!");
        log(`  Output: ${config.outputDir}`);
        log("\nYou can now run VRT tests that compare your Drupal SDC components");
        log("against this official KERN-UX reference implementation.");
    } catch (error) {
        logError(`Failed to generate reference Storybook: ${error instanceof Error ? error.message : String(error)}`);
        cleanup();
        process.exit(1);
    }
}

// Run the main function
main().catch((error: unknown) => {
    logError(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`);
    process.exit(1);
});
