const cp = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const yaml = require('js-yaml');

const backendDir = path.resolve(__dirname, '..');
const repoDir = path.resolve(backendDir, '..', '..');
const outputDir = path.join(backendDir, 'build', 'pkg-output');
const trayProject = path.join(repoDir, 'packages', 'windows-tray', 'Neta.Tray', 'Neta.Tray.csproj');
const trayOutputDir = path.join(backendDir, 'build', 'tray-output');
const nodeRuntimeDir = path.join(backendDir, 'build', 'node-runtime');
const skillsSourceDir = path.join(backendDir, 'skills');
const skillsOutputDir = path.join(backendDir, 'build', 'skills-output');
const toolsSourceDir = path.join(backendDir, 'tools', 'win32');
const toolsOutputDir = path.join(backendDir, 'build', 'tools-output', 'win32');
const issPath = path.join(backendDir, 'installer', 'setup.iss');
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';

function copyBundledNodeRuntime() {
  if (process.platform !== 'win32') {
    console.log('Skipping bundled node.exe copy on non-Windows host.');
    return;
  }

  fs.rmSync(nodeRuntimeDir, { recursive: true, force: true });
  fs.mkdirSync(nodeRuntimeDir, { recursive: true });
  fs.copyFileSync(process.execPath, path.join(nodeRuntimeDir, 'node.exe'));
}

function readSkillConfig(skillDir) {
  const configPath = path.join(skillDir, 'skill.config.yaml');
  if (!fs.existsSync(configPath)) return null;
  return yaml.load(fs.readFileSync(configPath, 'utf8')) || null;
}

function prepareSkillsOutput() {
  fs.rmSync(skillsOutputDir, { recursive: true, force: true });
  fs.cpSync(skillsSourceDir, skillsOutputDir, {
    recursive: true,
    filter: source => path.basename(source) !== 'node_modules',
  });

  for (const entry of fs.readdirSync(skillsOutputDir, { withFileTypes: true })) {
    if (!entry.isDirectory()) continue;

    const skillDir = path.join(skillsOutputDir, entry.name);
    const config = readSkillConfig(skillDir);
    const nodePackages = config?.runtime === 'node' && config?.entrypoint
      ? config?.dependencies?.node?.packages
      : null;
    if (!Array.isArray(nodePackages) || nodePackages.length === 0) continue;

    console.log(`Installing Node dependencies for skill ${entry.name}...`);
    cp.execFileSync(
      npmCmd,
      [
        'install',
        '--omit=dev',
        '--no-audit',
        '--no-fund',
        '--package-lock=false',
        ...nodePackages,
      ],
      { cwd: skillDir, stdio: 'inherit' }
    );
  }
}

if (!fs.existsSync(issPath)) {
  throw new Error(`缺少安装器脚本: ${issPath}`);
}

if (!fs.existsSync(path.join(outputDir, 'backend.exe'))) {
  console.log('backend.exe not found, running pkg build first...');
  cp.execFileSync('node', ['scripts/pkg-build.js'], { cwd: backendDir, stdio: 'inherit' });
}

copyBundledNodeRuntime();
prepareSkillsOutput();

fs.rmSync(trayOutputDir, { recursive: true, force: true });
cp.execFileSync(
  'dotnet',
  [
    'publish',
    trayProject,
    '-c', 'Release',
    '-r', 'win-x64',
    '--self-contained', 'true',
    '/p:PublishSingleFile=true',
    '/p:PublishTrimmed=false',
    '-o', trayOutputDir,
  ],
  { cwd: repoDir, stdio: 'inherit' }
);

const publishedTrayExePath = path.join(trayOutputDir, 'Neta.Tray.exe');
if (!fs.existsSync(publishedTrayExePath)) {
  throw new Error(`缺少托盘产物: ${publishedTrayExePath}`);
}

// 架构 C: 把 tools/win32/*.ps1 拷贝到 installer stage 目录(weixin-db 的 key 抽取脚本)
fs.rmSync(toolsOutputDir, { recursive: true, force: true });
fs.mkdirSync(toolsOutputDir, { recursive: true });
if (fs.existsSync(toolsSourceDir)) {
  fs.cpSync(toolsSourceDir, toolsOutputDir, { recursive: true });
  console.log(`[installer] copied tools/win32 → ${toolsOutputDir}`);
} else {
  console.warn(`[installer] tools/win32 not found at ${toolsSourceDir}, skip`);
}

const isccCandidates = [
  path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Inno Setup 6', 'ISCC.exe'),
  'C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe',
  'C:\\Program Files\\Inno Setup 6\\ISCC.exe',
];
const iscc = isccCandidates.find(p => fs.existsSync(p)) || 'iscc';

console.log('Building installer with Inno Setup...');
cp.execFileSync(iscc, [issPath], { cwd: backendDir, stdio: 'inherit' });
console.log('Installer build complete.');
