import { createHash } from "node:crypto";
import { execFile, execFileSync, spawn } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import http from "node:http";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { normalizeMachineCode, verifyLicense } from "./license.mjs";

const appDirectory = path.dirname(fileURLToPath(import.meta.url));
const packageRoot = path.resolve(appDirectory, "..");
const config = JSON.parse(readFileSync(path.join(appDirectory, "config.json"), "utf8"));
const dataRoot = path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "墨白");
const licensePath = path.join(dataRoot, "license.txt");
const siteURL = "http://127.0.0.1:3000/";
const activationURL = "http://127.0.0.1:2999/";
let siteProcess = null;
let activationServer = null;
let edgeProcess = null;

mkdirSync(dataRoot, { recursive: true });

function machineGuid() {
  try {
    const output = execFileSync("reg.exe", [
      "query",
      "HKLM\\SOFTWARE\\Microsoft\\Cryptography",
      "/v",
      "MachineGuid",
    ], { encoding: "utf8", windowsHide: true });
    const match = output.match(/MachineGuid\s+REG_SZ\s+([^\r\n]+)/i);
    if (match?.[1]) return match[1].trim().toUpperCase();
  } catch {}
  return `${os.hostname()}|${os.userInfo().username}`.toUpperCase();
}

const machineCode = createHash("sha256")
  .update(`mobai-desktop|${machineGuid()}`)
  .digest("hex")
  .slice(0, 32)
  .toUpperCase();

function formattedMachineCode() {
  return machineCode.match(/.{1,4}/g)?.join(" ") || machineCode;
}

function readLicense() {
  try {
    const code = readFileSync(licensePath, "utf8").trim();
    const result = verifyLicense({ code, publicKeyRaw: config.licensePublicKey, machineCode });
    return { code, ...result };
  } catch {
    return { valid: false, reason: "尚未激活" };
  }
}

function openEdge(url) {
  const profile = path.join(dataRoot, "BrowserProfile");
  const args = [
    `--app=${url}`,
    `--user-data-dir=${profile}`,
    "--no-first-run",
    "--disable-features=msEdgeSidebarV2",
  ];
  const candidates = [
    path.join(process.env.PROGRAMFILES || "C:\\Program Files", "Microsoft", "Edge", "Application", "msedge.exe"),
    path.join(process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)", "Microsoft", "Edge", "Application", "msedge.exe"),
  ];
  const executable = candidates.find(existsSync);
  if (executable) {
    edgeProcess = spawn(executable, args, { windowsHide: true });
    edgeProcess.once("exit", shutdown);
    return;
  }
  execFile("cmd.exe", ["/d", "/s", "/c", "start", "", url], { windowsHide: true });
}

function startSite() {
  if (siteProcess) return;
  siteProcess = spawn(process.execPath, [path.join(appDirectory, "site-server.mjs")], {
    cwd: packageRoot,
    windowsHide: true,
    stdio: "ignore",
    env: {
      ...process.env,
      MOBAI_SITE_HOST: "127.0.0.1",
      MOBAI_SITE_PORT: "3000",
      MOBAI_SITE_ROOT: path.join(packageRoot, "site"),
      MOBAI_NOTIFICATION_URL: config.notificationURL || "",
    },
  });
}

function activationHTML(message = "请输入管理后台签发的激活码。") {
  return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>墨白激活</title><style>
  *{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;background:radial-gradient(circle at 50% 18%,#fbfdf9,#edf3f0 58%,#e6ecea);color:#172126;font-family:"Microsoft YaHei UI",sans-serif}.card{width:min(570px,calc(100vw - 48px));padding:42px;border:1px solid #d7e0dd;border-radius:25px;background:rgba(255,255,255,.96);box-shadow:0 26px 85px rgba(24,43,45,.13)}.brand{display:flex;align-items:center;gap:14px;margin-bottom:30px}.mark{position:relative;width:48px;height:48px;border-radius:14px 14px 14px 5px;background:#172126}.mark i,.mark:before,.mark:after{content:"";position:absolute;left:13px;height:4px}.mark:before{top:13px;width:23px;background:#d9ed63}.mark i{top:22px;width:18px;background:#18a884}.mark:after{top:31px;width:13px;background:#f46b4e}.name{font-size:24px;font-weight:780}.eyebrow{color:#18a884;font-size:12px;font-weight:800;letter-spacing:.16em}.title{margin-top:8px;font-size:30px;font-weight:800}.status{margin-top:11px;color:#687579;font-size:14px;line-height:1.7}.machine-label,label{display:block;margin-top:25px;color:#687579;font-size:12px;font-weight:750}.machine{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px;padding:13px 14px;border:1px solid #d9e1de;border-radius:12px;background:#f6f9f7}.machine code{font-size:14px;font-weight:750;letter-spacing:.06em}.machine button{padding:0;background:transparent;color:#0a8d6c}textarea{width:100%;min-height:118px;margin-top:8px;padding:13px;border:1px solid #d9e1de;border-radius:12px;outline:none;resize:vertical;background:#fbfcfb;color:#172126;font:12px/1.6 Consolas,monospace}textarea:focus{border-color:#18a884;box-shadow:0 0 0 3px rgba(24,168,132,.12)}.actions{display:flex;justify-content:flex-end;margin-top:18px}button{height:45px;padding:0 24px;border:0;border-radius:12px;background:#172126;color:#fff;font-size:14px;font-weight:750;cursor:pointer}.error{color:#bc4b37}
  </style></head><body><main class="card"><div class="brand"><div class="mark"><i></i></div><div class="name">墨白</div></div><div class="eyebrow">LICENSE</div><div class="title">激活后开始使用</div><div id="status" class="status">${escapeHTML(message)}</div><div class="machine-label">本机机器码</div><div class="machine"><code id="machine">${formattedMachineCode()}</code><button onclick="navigator.clipboard.writeText('${machineCode}')">复制</button></div><label for="license">激活码</label><textarea id="license" spellcheck="false" placeholder="粘贴后台生成的 MB1 激活码"></textarea><div class="actions"><button onclick="activate()">激活</button></div></main><script>
  async function activate(){const status=document.getElementById('status');status.textContent='正在校验…';status.className='status';const response=await fetch('/activate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({code:document.getElementById('license').value.trim()})});const data=await response.json();if(!response.ok){status.textContent=data.message||'激活失败';status.className='status error';return}status.textContent='激活成功，正在进入墨白…';setTimeout(()=>location.replace('${siteURL}'),600)}
  </script></body></html>`;
}

function escapeHTML(value) {
  return String(value).replace(/[&<>"']/g, (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]);
}

function startActivation(message) {
  activationServer = http.createServer((request, response) => {
    if (request.method === "POST" && request.url === "/activate") {
      let body = "";
      request.on("data", (chunk) => { body += chunk; });
      request.on("end", () => {
        try {
          const code = JSON.parse(body).code || "";
          const result = verifyLicense({ code, publicKeyRaw: config.licensePublicKey, machineCode });
          if (!result.valid) throw new Error(result.reason);
          writeFileSync(licensePath, code.trim(), "utf8");
          startSite();
          response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
          response.end(JSON.stringify({ ok: true }));
        } catch (error) {
          response.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
          response.end(JSON.stringify({ ok: false, message: error instanceof Error ? error.message : "激活失败" }));
        }
      });
      return;
    }
    response.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
    response.end(activationHTML(message));
  });
  activationServer.listen(2999, "127.0.0.1", () => openEdge(activationURL));
}

function shutdown() {
  if (siteProcess && !siteProcess.killed) siteProcess.kill();
  activationServer?.close();
  setTimeout(() => process.exit(0), 300).unref();
}

process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
process.on("exit", () => { if (siteProcess && !siteProcess.killed) siteProcess.kill(); });

const license = readLicense();
if (license.valid) {
  startSite();
  setTimeout(() => openEdge(siteURL), 500);
} else {
  startActivation(license.reason || "请输入管理后台签发的激活码。");
}
