import { defaultServerConditions, defaultServerMainFields, defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { fileURLToPath, fs, isBuiltin, path } from "@vrtmrz/livesync-commonlib/node";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const resolve = (...args: string[]) => path.resolve(...args).replace(/\\/g, "/");
const repoRoot = path.resolve(__dirname, "../../..");

function readVersion(filePath: string): string | undefined {
    const parsed: unknown = JSON.parse(fs.readFileSync(filePath, "utf-8"));
    if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) {
        return undefined;
    }
    return typeof parsed.version === "string" ? parsed.version : undefined;
}

const packageVersion = readVersion(path.resolve(repoRoot, "package.json"));
const manifestVersion = readVersion(path.resolve(repoRoot, "manifest.json"));
// https://vite.dev/config/
const defaultExternal = [
    "obsidian",
    "electron",
    "crypto",
    "pouchdb-adapter-leveldb",
    "commander",
    "chokidar",
    "punycode",
    "werift",
];
// Polyfill FileReader at the very top of the CJS bundle. octagonal-wheels uses
// FileReader for base64 conversion when Uint8Array.toBase64 (TC39 proposal) is
// unavailable. Node.js has neither, so we inject a minimal FileReader shim before
// any module-scope code evaluates.
const fileReaderPolyfillBanner = `
if (typeof globalThis.FileReader === "undefined") {
    globalThis.FileReader = class FileReader {
        constructor() { this.result = null; this.onload = null; this.onerror = null; }
        readAsDataURL(blob) {
            blob.arrayBuffer().then((buf) => {
                var b64 = require("buffer").Buffer.from(buf).toString("base64");
                this.result = "data:" + (blob.type || "application/octet-stream") + ";base64," + b64;
                if (this.onload) this.onload({ target: this });
            }).catch((err) => { if (this.onerror) this.onerror({ target: this, error: err }); });
        }
        readAsArrayBuffer() { throw new Error("FileReader.readAsArrayBuffer is not implemented in this polyfill"); }
        readAsBinaryString() { throw new Error("FileReader.readAsBinaryString is not implemented in this polyfill"); }
        readAsText() { throw new Error("FileReader.readAsText is not implemented in this polyfill"); }
        abort() { throw new Error("FileReader.abort is not implemented in this polyfill"); }
    };
}
`;

function injectBanner(): import("vite").Plugin {
    return {
        name: "inject-banner",
        generateBundle(_options, bundle) {
            for (const chunk of Object.values(bundle)) {
                if (chunk.type === "chunk" && chunk.isEntry) {
                    // Insert after the shebang line if present, otherwise at the top.
                    if (chunk.code.startsWith("#!")) {
                        const newline = chunk.code.indexOf("\n");
                        chunk.code =
                            chunk.code.slice(0, newline + 1) + fileReaderPolyfillBanner + chunk.code.slice(newline + 1);
                    } else {
                        chunk.code = fileReaderPolyfillBanner + chunk.code;
                    }
                }
            }
        },
    };
}

const buildInputs: Record<string, string> = {
    index: resolve(__dirname, "entrypoint.ts"),
};
if (process.env.LIVESYNC_CLI_TEST_SUPPORT === "1") {
    buildInputs["p2p-lifecycle-test"] = resolve(__dirname, "test-support/p2p-lifecycle-entrypoint.ts");
}

export default defineConfig({
    plugins: [svelte(), injectBanner()],
    resolve: {
        // This bundle runs in Node. Vite's client defaults include the `browser`
        // export condition, which would select Commonlib's inline Web Worker.
        conditions: [...defaultServerConditions],
        mainFields: [...defaultServerMainFields],
        alias: {
            // The CLI runs on Node.js; force AWS XML builder to its CJS Node entry
            // so Vite does not resolve the browser DOMParser-based XML parser.
            "@aws-sdk/xml-builder": resolve(__dirname, "../../../node_modules/@aws-sdk/xml-builder/dist-cjs/index.js"),
            // Force fflate to the Node CJS entry; browser entry expects Web Worker globals.
            fflate: resolve(__dirname, "../../../node_modules/fflate/lib/node.cjs"),
            "@": resolve(__dirname, "../../"),
        },
    },

    base: "./",
    build: {
        outDir: "dist",
        emptyOutDir: true,
        minify: false,
        rollupOptions: {
            input: buildInputs,
            external: (id) => {
                if (isBuiltin(id)) return true;
                if (defaultExternal.includes(id)) return true;
                if (id.startsWith(".") || id.startsWith("/")) return false;
                if (id.startsWith("@/")) return false;
                if (id.endsWith(".ts") || id.endsWith(".js")) return false;
                if (id.startsWith("pouchdb-")) return true;
                if (id.startsWith("werift")) return true;
                return false;
            },
        },
        lib: {
            entry: resolve(__dirname, "entrypoint.ts"),
            formats: ["cjs"],
            fileName: (_format, entryName) => `${entryName}.cjs`,
        },
    },
    define: {
        self: "globalThis",
        global: "globalThis",
        nonInteractive: "true",
        // localStorage: "undefined", // Prevent usage of localStorage in the CLI environment
        MANIFEST_VERSION: JSON.stringify(process.env.MANIFEST_VERSION || manifestVersion || "0.0.0"),
        PACKAGE_VERSION: JSON.stringify(process.env.PACKAGE_VERSION || packageVersion || "0.0.0"),
    },
});
