// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { build } from "vite";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";
import { copyFileSync, mkdirSync, cpSync, existsSync } from "fs";
import { execSync } from "child_process";
import chalk from "chalk";

const __dirname = dirname(fileURLToPath(import.meta.url));

// Helper function to create Vite build options that avoid TypeScript plugin conflicts
function createBuildOptions(outDir, options = {}) {
    return {
        configFile: false,
        logLevel: "error",
        plugins: [
            // Explicitly disable TypeScript plugin to avoid outDir conflicts
            {
                name: "disable-typescript-plugin",
                configResolved(config) {
                    // Remove TypeScript plugin
                    config.plugins = config.plugins.filter(
                        (plugin) =>
                            !plugin.name || !plugin.name.includes("typescript"),
                    );
                },
            },
        ],
        esbuild: {
            // Use esbuild for TypeScript compilation
            target: "es2022",
        },
        build: {
            outDir,
            emptyOutDir: options.emptyOutDir ?? false,
            sourcemap: isDev,
            minify: !isDev,
            rollupOptions: options.rollupOptions || {},
        },
    };
}

const isDev =
    process.argv.includes("--dev") ||
    process.argv.includes("--mode=development");
const buildMode = isDev ? "development" : "production";
const verbose = process.argv.includes("--verbose");

const chromeOutDir = resolve(__dirname, "../dist/extension");
const electronOutDir = resolve(__dirname, "../dist/electron");
const srcDir = resolve(__dirname, "../src/extension");
const electronSrcDir = resolve(__dirname, "../src/electron");

const sharedScripts = {
    contentScript: "contentScript/index.ts",
    webTypeAgentMain: "webTypeAgentMain.ts",
    webTypeAgentContentScript: "webTypeAgentContentScript.ts",
    "views/options": "views/options.ts",
    "views/pageMacros": "views/pageMacros.ts",
    "views/macrosLibrary": "views/macrosLibrary.ts",
    "views/entityGraphView": "views/entityGraphView.ts",
    "views/topicGraphView": "views/topicGraphView.ts",
    "views/pageKnowledge": "views/pageKnowledge.ts",
    "views/pageQnA": "views/pageQnA.ts",
    "views/annotationsLibrary": "views/annotationsLibrary.ts",
    "views/knowledgeLibrary": "views/knowledgeLibrary.ts",
    "views/pdfView": "views/pdfView.ts",
    "views/chatPanel": "views/chatPanel.ts",
    uiEventsDispatcher: "uiEventsDispatcher.ts",
    "sites/crossword": "sites/crossword.ts",
    "sites/commerce": "sites/commerce.ts",
    "sites/instacart": "sites/instacart.ts",
    "sites/paleobiodb": "sites/paleobiodb.ts",
    "sites/webflow": "sites/webflow.ts",
    "offscreen/contentProcessor": "offscreen/contentProcessor.ts",
    "offscreen/screenshotCapture": "offscreen/screenshotCapture.ts",
};

const electronOnlyScripts = {
    agentActivation: "../src/electron/agentActivation.ts",
};

const vendorAssets = [
    [
        "node_modules/bootstrap/dist/css/bootstrap.min.css",
        "vendor/bootstrap/bootstrap.min.css",
    ],
    [
        "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
        "vendor/bootstrap/bootstrap.bundle.min.js",
    ],
    ["node_modules/prismjs/prism.js", "vendor/prism/prism.js"],
    ["node_modules/prismjs/themes/prism.css", "vendor/prism/prism.css"],
    [
        "node_modules/prismjs/components/prism-typescript.js",
        "vendor/prism/prism-typescript.js",
    ],
    [
        "node_modules/prismjs/components/prism-json.js",
        "vendor/prism/prism-json.js",
    ],
    [
        "node_modules/prismjs/components/prism-yaml.js",
        "vendor/prism/prism-yaml.js",
    ],
    // Cytoscape libraries for entity graph visualization
    [
        "node_modules/cytoscape/dist/cytoscape.min.js",
        "vendor/cytoscape/cytoscape.min.js",
    ],
    ["node_modules/dagre/dist/dagre.min.js", "vendor/dagre/dagre.min.js"],
    [
        "node_modules/cytoscape-dagre/cytoscape-dagre.js",
        "vendor/cytoscape-dagre/cytoscape-dagre.min.js",
    ],
];

const libraryAssets = [
    "views/annotationsLibrary.css",
    "views/annotationsLibrary.html",
    "views/entityGraphView.css",
    "views/entityGraphView.html",
    "views/topicGraphView.css",
    "views/topicGraphView.html",
    "views/knowledgeLibrary.css",
    "views/knowledgeLibrary.html",
    "views/macrosLibrary.css",
    "views/macrosLibrary.html",
    "views/options.css",
    "views/options.html",
    "views/pageKnowledge.css",
    "views/pageKnowledge.html",
    "views/pageMacros.css",
    "views/pageMacros.html",
    "views/pageQnA.css",
    "views/pageQnA.html",
    "views/pdfView.css",
    "views/pdfView.html",
    "views/chatPanel.css",
    "views/chatPanel.html",
];

function copyLibraryAssets(outDir) {
    mkdirSync(`${outDir}/views`, { recursive: true });
    for (const asset of libraryAssets) {
        copyFileSync(`${srcDir}/${asset}`, `${outDir}/${asset}`);
    }
}

function copyCommonStaticAssets(outDir) {
    // Copy library assets
    copyLibraryAssets(outDir);

    // Copy shared chat-ui CSS into views/ so chatPanel.css can @import it
    const chatUiCss = resolve(__dirname, "../../../chat-ui/styles/chat.css");
    copyFileSync(chatUiCss, `${outDir}/views/chat-ui.css`);

    // Copy other common assets
    mkdirSync(`${outDir}/offscreen`, { recursive: true });
    copyFileSync(
        `${srcDir}/offscreen/offscreen.html`,
        `${outDir}/offscreen/offscreen.html`,
    );
    copyFileSync(
        `${srcDir}/offscreen/screenshotCapture.html`,
        `${outDir}/offscreen/screenshotCapture.html`,
    );

    mkdirSync(`${outDir}/sites`, { recursive: true });
    copyFileSync(
        `${srcDir}/sites/paleobiodbSchema.mts`,
        `${outDir}/sites/paleobiodbSchema.mts`,
    );

    cpSync(`${srcDir}/images`, `${outDir}/images`, { recursive: true });

    // Copy vendor assets
    for (const [src, destRel] of vendorAssets) {
        const dest = resolve(outDir, destRel);
        mkdirSync(dirname(dest), { recursive: true });
        copyFileSync(resolve(__dirname, "../", src), dest);
    }
}

if (verbose)
    console.log(
        chalk.blueBright(
            `\n🔨 Building in ${buildMode.toUpperCase()} mode...\n`,
        ),
    );

// Path to crossword grammar source (used later for compilation)
const crosswordAgrPath = resolve(
    srcDir,
    "webagent/crossword/crosswordSchema.agr",
);

//
// ------------------------
// 🔹 Browser Extension
// ------------------------
//
if (verbose) console.log(chalk.cyan("🚀 Building Browser extension..."));

// Service worker (ESM)
await build(
    createBuildOptions(chromeOutDir, {
        emptyOutDir: !isDev,
        rollupOptions: {
            input: { serviceWorker: resolve(srcDir, "serviceWorker/index.ts") },
            output: {
                format: "es",
                entryFileNames: "serviceWorker.js",
            },
        },
    }),
);
if (verbose) console.log(chalk.green("✅ Chrome service worker built"));

// Content scripts (IIFE)
for (const [name, relPath] of Object.entries(sharedScripts)) {
    const input = resolve(srcDir, relPath);
    if (verbose) console.log(chalk.yellow(`➡️  Chrome content: ${name}`));
    await build(
        createBuildOptions(chromeOutDir, {
            rollupOptions: {
                input,
                output: {
                    format: "iife",
                    entryFileNames: `${name}.js`,
                    inlineDynamicImports: true,
                },
            },
        }),
    );
    if (verbose) console.log(chalk.green(`✅ Chrome ${name}.js built`));
}

// Static file copy
if (verbose) console.log(chalk.cyan("\n📁 Copying Chrome static files..."));
copyFileSync(`${srcDir}/manifest.json`, `${chromeOutDir}/manifest.json`);
copyCommonStaticAssets(chromeOutDir);

// Compile and copy WebAgent grammars
if (verbose) console.log(chalk.cyan("📝 Compiling WebAgent grammars..."));
const chromeGrammarPath = resolve(
    chromeOutDir,
    "webagent/crossword/crosswordSchema.ag.json",
);
if (existsSync(crosswordAgrPath)) {
    mkdirSync(dirname(chromeGrammarPath), { recursive: true });
    try {
        execSync(`npx agc -i "${crosswordAgrPath}" -o "${chromeGrammarPath}"`, {
            cwd: resolve(__dirname, ".."),
            stdio: verbose ? "inherit" : "pipe",
        });
        if (verbose) console.log(chalk.green("✅ Crossword grammar compiled"));
    } catch (error) {
        console.error(
            chalk.red("❌ Failed to compile crossword grammar:"),
            error.message,
        );
        process.exit(1);
    }
} else {
    if (verbose)
        console.log(
            chalk.yellow("⚠️  Crossword grammar file not found, skipping"),
        );
}

if (verbose) console.log(chalk.green("✅ Chrome static assets copied"));

//
// ------------------------
// 🟣 Electron Extension
// ------------------------
//
if (verbose) console.log(chalk.cyan("\n🚀 Building Electron extension..."));

for (const [name, relPath] of Object.entries(sharedScripts)) {
    const input = resolve(srcDir, relPath);
    if (verbose) console.log(chalk.yellow(`➡️  Electron shared: ${name}`));
    await build(
        createBuildOptions(electronOutDir, {
            rollupOptions: {
                input,
                output: {
                    format: "iife",
                    entryFileNames: `${name}.js`,
                    inlineDynamicImports: true,
                },
            },
        }),
    );
    if (verbose) console.log(chalk.green(`✅ Electron ${name}.js built`));
}

for (const [name, relPath] of Object.entries(electronOnlyScripts)) {
    const input = resolve(__dirname, relPath);
    if (verbose) console.log(chalk.yellow(`➡️  Electron only: ${name}`));
    await build(
        createBuildOptions(electronOutDir, {
            rollupOptions: {
                input,
                output: {
                    format: "iife",
                    entryFileNames: `${name}.js`,
                    inlineDynamicImports: true,
                },
            },
        }),
    );
    if (verbose) console.log(chalk.green(`✅ Electron ${name}.js built`));
}

// Copy electron manifest and assets
if (verbose) console.log(chalk.cyan("\n📁 Copying Electron static files..."));
copyFileSync(
    `${electronSrcDir}/manifest.json`,
    `${electronOutDir}/manifest.json`,
);
copyCommonStaticAssets(electronOutDir);

// Copy compiled WebAgent grammars to electron output
if (existsSync(chromeGrammarPath)) {
    const electronGrammarDir = resolve(electronOutDir, "webagent/crossword");
    mkdirSync(electronGrammarDir, { recursive: true });
    copyFileSync(
        chromeGrammarPath,
        resolve(electronGrammarDir, "crosswordSchema.ag.json"),
    );
    if (verbose)
        console.log(chalk.green("✅ Crossword grammar copied to Electron"));
}

if (verbose) console.log(chalk.green("✅ Electron static assets copied\n"));

// Update build hash to mark successful completion
// updateBuildHash(true); // true = actually built something

if (verbose)
    console.log(
        chalk.bold.green(
            `\n🎉 Extension build complete [${buildMode.toUpperCase()} mode]`,
        ),
    );
