#!/usr/bin/env node
const { spawnSync } = require("node:child_process");
const path = require("node:path");

const UNINSTALL_MODE = process.argv.includes("--uninstall");
const SKIP_PIP_INSTALL = process.env.BUILD_CORPUS_SKIP_PIP_INSTALL === "1";

const packageRoot = path.resolve(__dirname, "..");
const candidates = process.platform === "win32" ? ["py", "python"] : ["python3", "python"];
const requirements = path.join(packageRoot, "requirements.txt");

function isGlobalInstall() {
  return process.env.npm_config_global === "true";
}

function printUsage() {
  const isGlobal = isGlobalInstall();
  if (isGlobal) {
    console.log("Build Corpus installed globally. Run: build-corpus --help");
    return;
  }

  console.log("Build Corpus installed locally.");
  console.log("Run with: npx build-corpus --help");
}

function warnOnShadowedWindowsCommand() {
  if (process.platform !== "win32") return;

  const whereResult = spawnSync("where.exe", ["build-corpus"], { encoding: "utf8" });
  if (whereResult.error || whereResult.status !== 0) return;

  const matches = whereResult.stdout
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);
  if (matches.length === 0) return;

  const firstMatch = matches[0].toLowerCase();
  if (!firstMatch.includes("python") || !firstMatch.endsWith("build-corpus.exe")) return;

  console.warn("");
  console.warn("WARNING: 'build-corpus' currently resolves to a Python executable:");
  console.warn(`  ${matches[0]}`);
  console.warn("That usually means a stale pip install is shadowing the npm command.");
  console.warn("Fix it with: py -3 -m pip uninstall build-corpus");
  console.warn("Then rerun your npm install or use: npx build-corpus --help");
}

function installWindowsContextMenu() {
  if (process.platform !== "win32") return;
  if (!isGlobalInstall()) return;
  if (process.env.BUILD_CORPUS_SKIP_WINDOWS_MENU === "1") return;

  const prefix = process.env.npm_config_prefix || path.join(process.env.APPDATA || "", "npm");
  const commandPath = path.join(prefix, "build-corpus.cmd");
  const editorPath = path.join(prefix, "build-corpus-editor.cmd");
  const nativeEditorPath = path.join(packageRoot, "dist", "windows-editor", "BuildCorpusEditor.exe");
  const editorCommandPath = fileExists(nativeEditorPath) ? nativeEditorPath : editorPath;
  const markdownInputMenus = [".docx", ".pptx", ".ppt"].map((extension) => ({
      keyName: "BuildCorpusToMarkdown",
      label: "Convert to Markdown",
      commandValue: `"${commandPath}" "%1" --out-same-dir`,
      extension,
    }));
  const menus = [
    ...markdownInputMenus,
    {
      keyName: "BuildCorpusFolderToMarkdown",
      label: "Convert Documents to Markdown",
      commandValue: `"${commandPath}" "%V" --out-same-dir`,
      extension: "Directory",
    },
    ...(process.env.BUILD_CORPUS_SKIP_EDITOR === "1" ? [] : [
      {
        keyName: "BuildCorpusOpenEditor",
        label: "Open in regen-mde",
        commandValue: `"${editorCommandPath}" "%1"`,
        extension: ".docx",
      },
      {
        keyName: "BuildCorpusOpenEditor",
        label: "Open in regen-mde",
        commandValue: `"${editorCommandPath}" "%1"`,
        extension: ".md",
      },
    ]),
    {
      keyName: "BuildCorpusToWord",
      label: "Convert to Word",
      commandValue: `"${commandPath}" "%1" --to word --out-same-dir`,
      extension: ".md",
    },
    {
      keyName: "BuildCorpusInlineImages",
      label: "Inline Markdown Images",
      commandValue: `"${commandPath}" "%1" --inline-images`,
      extension: ".md",
    },
  ];

  for (const menu of menus) {
    const shellBase = menu.extension === "Directory"
      ? "HKCU\\Software\\Classes\\Directory\\shell"
      : `HKCU\\Software\\Classes\\SystemFileAssociations\\${menu.extension}\\shell`;
    const commands = [
      ["delete", `${shellBase}\\Life AI`, "/f"],
      ["delete", `HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\LifeAI.${menu.keyName}`, "/f"],
      ["delete", `HKCU\\Software\\LifeAI\\ShellCommands\\${menu.keyName}`, "/f"],
      ["add", `${shellBase}\\${menu.keyName}`, "/v", "MUIVerb", "/d", menu.label, "/f"],
      ["add", `${shellBase}\\${menu.keyName}`, "/v", "Icon", "/t", "REG_EXPAND_SZ", "/d", menu.keyName === "BuildCorpusOpenEditor" ? editorCommandPath : commandPath, "/f"],
      ["add", `${shellBase}\\${menu.keyName}\\command`, "/ve", "/d", menu.commandValue, "/f"],
    ];

    for (const args of commands) {
      const result = spawnSync("reg.exe", args, { stdio: "inherit" });
      const status = result.status ?? 1;
      if (args[0] === "delete" && status === 1 && !result.error) {
        continue;
      }
      if (result.error || status !== 0) {
        console.warn(`Build Corpus could not add the Windows ${menu.extension} context menu.`);
        return;
      }
    }
  }
  spawnSync("reg.exe", ["add", "HKCU\\Software\\Classes\\.md", "/v", "Content Type", "/d", "text/markdown", "/f"], { stdio: "inherit" });
  spawnSync("reg.exe", ["add", "HKCU\\Software\\Classes\\.md\\ShellNew", "/v", "NullFile", "/t", "REG_SZ", "/d", "", "/f"], { stdio: "inherit" });

  console.log("Windows Explorer menus added for .docx, .pptx, .ppt, .md, folders, and New Markdown Document");
}

function fileExists(candidate) {
  try {
    return require("node:fs").existsSync(candidate);
  } catch {
    return false;
  }
}

function uninstallWindowsContextMenu() {
  if (process.platform !== "win32") return 0;

  const menus = [
    { extension: ".docx", keyName: "BuildCorpusToMarkdown" },
    { extension: ".pptx", keyName: "BuildCorpusToMarkdown" },
    { extension: ".ppt", keyName: "BuildCorpusToMarkdown" },
    { extension: ".docx", keyName: "BuildCorpusOpenEditor" },
    { extension: ".md", keyName: "BuildCorpusOpenEditor" },
    { extension: ".md", keyName: "BuildCorpusToWord" },
    { extension: ".md", keyName: "BuildCorpusInlineImages" },
    { extension: "Directory", keyName: "BuildCorpusFolderToMarkdown" },
  ];

  let exitCode = 0;
  for (const menu of menus) {
    const shellBase = menu.extension === "Directory"
      ? `HKCU\\Software\\Classes\\Directory\\shell`
      : `HKCU\\Software\\Classes\\SystemFileAssociations\\${menu.extension}\\shell`;
    const removals = [
      `${shellBase}\\BuildCorpus`,
      `${shellBase}\\${menu.keyName}`,
      `${shellBase}\\Life AI`,
      `HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\LifeAI.${menu.keyName}`,
      `HKCU\\Software\\LifeAI\\ShellCommands\\${menu.keyName}`,
    ];

    for (const key of removals) {
      const result = spawnSync("reg.exe", ["delete", key, "/f"], { stdio: "inherit" });
      const status = result.status ?? 1;
      if (result.error || (status !== 0 && status !== 1)) {
        console.warn(`Build Corpus could not remove the Windows ${menu.extension} context menu.`);
        exitCode = 1;
      }
    }
  }
  spawnSync("reg.exe", ["delete", "HKCU\\Software\\Classes\\.md\\ShellNew", "/f"], { stdio: "inherit" });

  console.log("Windows Explorer menus removed for .docx, .pptx, .ppt, .md, and folders");
  return exitCode;
}

if (UNINSTALL_MODE) {
  process.exit(uninstallWindowsContextMenu());
}

if (SKIP_PIP_INSTALL) {
  printUsage();
  installWindowsContextMenu();
  warnOnShadowedWindowsCommand();
  process.exit(0);
}

function pipInstallArgs(candidate, extraFlags) {
  const base = candidate === "py"
    ? ["-3", "-m", "pip", "install", "-r", requirements]
    : ["-m", "pip", "install", "-r", requirements];
  return [...base, ...extraFlags];
}

// Install the Python dependencies for one interpreter candidate.
// On Windows we make a single attempt (PEP 668 does not apply). On Linux/macOS
// modern distros mark the system Python "externally managed" (PEP 668), so a
// bare `pip install` aborts; fall back to user-site, then --break-system-packages.
// Returns { found } so the caller can try the next interpreter on ENOENT, and
// { status } for the best attempt.
function installPythonDeps(candidate) {
  const attempts = process.platform === "win32"
    ? [[]]
    : [[], ["--user"], ["--break-system-packages"]];

  let lastStatus = 1;
  for (const extraFlags of attempts) {
    const result = spawnSync(candidate, pipInstallArgs(candidate, extraFlags), { stdio: "inherit" });
    if (result.error && result.error.code === "ENOENT") return { found: false, status: 1 };
    lastStatus = result.status ?? 1;
    if (lastStatus === 0) return { found: true, status: 0 };
  }
  return { found: true, status: lastStatus };
}

function warnLinuxDependencyFallback() {
  console.warn("");
  console.warn("Build Corpus could not install its Python dependencies automatically.");
  console.warn("On Debian/Ubuntu the system Python is externally managed (PEP 668).");
  console.warn("Install the dependencies into your user site manually:");
  console.warn("  python3 -m pip install --user -r requirements.txt");
}

for (const candidate of candidates) {
  const { found, status } = installPythonDeps(candidate);
  if (!found) continue;

  if (status !== 0) {
    // Windows treats a pip failure as fatal; on Linux/macOS we never fail the
    // npm install over PEP 668 — the CLI still works once deps are present.
    if (process.platform === "win32") {
      process.exit(status);
    }
    warnLinuxDependencyFallback();
    printUsage();
    process.exit(0);
  }

  printUsage();
  installWindowsContextMenu();
  warnOnShadowedWindowsCommand();
  process.exit(0);
}

console.warn("Build Corpus could not find Python to install Python dependencies.");
if (process.platform !== "win32") {
  console.warn("Install Python 3.10+ (e.g. `sudo apt install python3 python3-pip`), then re-run the install.");
}
printUsage();
installWindowsContextMenu();
process.exit(0);
