// AGENT 破甲 - Electron main process
const { app, BrowserWindow, ipcMain, shell } = require('electron');
const path = require('path');
const fs = require('fs');
const license = require('./license');
const skills = require('./skills');
const updater = require('./updater');

updater.init(license.APP_VERSION);

let win = null;
const logLines = [];
function pushLog(line) {
  const ts = new Date().toISOString();
  logLines.push(`[${ts}] ${line}`);
  if (logLines.length > 500) logLines.shift();
  if (win && !win.isDestroyed()) win.webContents.send('log:append', logLines[logLines.length - 1]);
}

const ALLOWED_PROTOCOLS = ['https:', 'http:', 'mailto:', 'tencent:'];
function openExternalSafe(url) {
  try {
    const u = new URL(url);
    if (!ALLOWED_PROTOCOLS.includes(u.protocol)) return { ok: false, reason: 'blocked-protocol' };
    return shell.openExternal(url)
      .then(() => ({ ok: true }))
      .catch(e => { pushLog('打开外链失败: ' + e.message); return { ok: false, reason: 'open-failed' }; });
  } catch { return { ok: false, reason: 'bad-url' }; }
}

function createWindow() {
  win = new BrowserWindow({
    width: 1180, height: 760, minWidth: 900, minHeight: 620,
    title: 'AGENT 破甲',
    backgroundColor: '#f5f7fa',
    autoHideMenuBar: true,
    webPreferences: {
      preload: path.join(__dirname, 'preload.cjs'),
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: true
    }
  });

  // 新建窗口请求：一律拒绝，只按白名单协议交给系统浏览器
  win.webContents.setWindowOpenHandler(({ url }) => {
    openExternalSafe(url);
    return { action: 'deny' };
  });

  // 主窗口禁止被导航走（dev 模式放行 vite dev server）
  win.webContents.on('will-navigate', (e, url) => {
    const devUrl = process.env.VITE_DEV_SERVER_URL;
    if (devUrl && url.startsWith(devUrl)) return;
    e.preventDefault();
  });

  if (process.env.VITE_DEV_SERVER_URL) {
    win.loadURL(process.env.VITE_DEV_SERVER_URL);
  } else {
    win.loadFile(path.join(__dirname, '..', 'dist-ui', 'index.html'));
  }
}

app.whenReady().then(() => {
  createWindow();
  // bootstrap re-validation
  const s = license.status();
  pushLog('应用启动 v' + license.APP_VERSION);
  if (s.activated) { pushLog('许可有效: ' + s.license_type + ' / ' + s.serial); license.touch(); }
  else pushLog('未激活' + (s.reason ? '（' + s.reason + '）' : '') + '，请前往「激活许可」页输入激活码');
  // periodic update check (silent)
  updater.checkUpdate().then(r => {
    if (r.ok && r.hasUpdate) pushLog('发现新版本 ' + r.version + '，可前往官网下载');
    else if (!r.ok) pushLog('更新检查: ' + (r.reason || '失败') + '（非阻塞）');
  });
});

app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });

function requireActivated() {
  return license.status().activated;
}

// 安装/卸载互斥：避免切页重复点击导致并发写同一目标目录
let skillsBusy = null;
function withSkillsLock(fn) {
  if (skillsBusy) return Promise.resolve({ ok: false, reason: 'busy' });
  skillsBusy = Promise.resolve()
    .then(fn)
    .finally(() => { skillsBusy = null; });
  return skillsBusy;
}

ipcMain.handle('license:status', () => license.status());
ipcMain.handle('license:activate', (_e, token) => {
  if (typeof token !== 'string' || !token.trim()) return { ok: false, reason: 'bad-token' };
  if (token.length > 8192) return { ok: false, reason: 'token-too-long' };
  const r = license.activate(token.trim());
  pushLog(r.ok ? '激活成功 ' + r.payload.serial : '激活失败 ' + r.reason);
  return r;
});
ipcMain.handle('license:deactivate', () => {
  try { fs.unlinkSync(license.licenseFile()); pushLog('已注销本机许可'); return { ok: true }; }
  catch (e) { pushLog('注销失败: ' + e.message); return { ok: false, reason: 'unlink-failed' }; }
});
ipcMain.handle('skills:list', () => skills.listBundled());
ipcMain.handle('skills:targets', () => skills.detectTargets());
ipcMain.handle('skills:install', (_e, target, names) => {
  if (!requireActivated()) { pushLog('安装被拒绝：未激活'); return { ok: false, reason: 'not-activated' }; }
  const list = Array.isArray(names) ? names : [];
  pushLog('安装技能 -> ' + target + (list.length ? ': ' + list.length + ' 项' : '（规则文件）'));
  return withSkillsLock(() => skills.install(target, list));
});
ipcMain.handle('skills:uninstall', (_e, target, names) => {
  if (!requireActivated()) { pushLog('卸载被拒绝：未激活'); return { ok: false, reason: 'not-activated' }; }
  const list = Array.isArray(names) ? names : [];
  pushLog('卸载技能 <- ' + target);
  return withSkillsLock(() => skills.uninstall(target, list));
});
ipcMain.handle('log:list', () => logLines);
ipcMain.handle('update:check', () => updater.checkUpdate());
ipcMain.handle('update:download', async (_e, url, sha512) => {
  pushLog('开始下载更新包…');
  const r = await updater.downloadAndVerify(url, sha512);
  if (!r.ok) { pushLog('更新包下载/校验失败: ' + r.reason); return r; }
  if (process.platform === 'win32') {
    pushLog('更新包校验通过（sha512），正在打开安装程序');
    const err = await shell.openPath(r.path);
    if (err) { pushLog('打开安装程序失败: ' + err); return { ok: false, reason: 'open-failed' }; }
    return { ok: true };
  }
  // macOS：解压 zip 不会替换应用，定位到文件让用户手动替换
  pushLog('更新包校验通过（sha512），请在访达中手动替换应用');
  shell.showItemInFolder(r.path);
  return { ok: true, manual: true };
});
ipcMain.handle('app:version', () => license.APP_VERSION);
ipcMain.handle('app:openExternal', (_e, url) => openExternalSafe(url));
