// ============================================================
// build.mjs — 构建总管
//
// 用法：node build/build.mjs [选项]
//
// 平台（必选其一）：
//   --win            Windows
//   --mac            macOS
//   --linux          Linux
//
// 版本 & 渠道：
//   --edition <e>    版本类型：personal（默认）| enterprise
//   --channel <c>    发布渠道：stable（默认）| beta | alpha
//   --version <v>    覆盖 package.json 中的版本号
//
// 操作（可选组合，默认只执行 --build）：
//   --build          仅构建（默认）
//   --clean          构建前清理 release/ dist/ dist-electron/
//   --sign           代码签名
//   --upload         上传安装包到 OSS
//   --publish        发布版本信息到后端 API
//   --all            全流程（clean + build + sign + upload + publish）
//
// 签名（仅 --sign 时可用）：
//   --cert <path>        证书文件路径 (.pfx)
//   --cert-password <p>  证书密码
//
// OSS 路径规则：
//   Stable → releases/{version}/            （向后兼容，无渠道后缀）
//   Beta   → releases/beta/{version}/       （独立生命周期，可设自动过期策略）
//   Alpha  → releases/{version}/alpha/       （版本优先）
//
// 示例：
//   node build/build.mjs --win
//   node build/build.mjs --win --channel beta --upload --publish
//   node build/build.mjs --win --edition enterprise --all
//   node build/build.mjs --win --sign --cert ./cert.pfx --cert-password xxx
// ============================================================

import { spawn, execSync } from 'node:child_process';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');
const SCRIPTS = join(__dirname, 'scripts');

// ANSI 颜色
const c = (code, text) => `\x1b[${code}m${text}\x1b[0m`;
const dim  = (t) => c(2, t);
const bold = (t) => c(1, t);
const cyan = (t) => c(36, t);
const green = (t) => c(32, t);
const yellow = (t) => c(33, t);

// ---------- 参数解析 ----------

const args = process.argv.slice(2);

const opts = {
  win: false,
  mac: false,
  linux: false,
  clean: false,
  build: false,
  sign: false,
  upload: false,
  publish: false,
  cert: '',
  certPassword: '',
  edition: 'personal',
  channel: 'stable',
  version: '',
};

let i = 0;
while (i < args.length) {
  const a = args[i];
  switch (a) {
    case '--win':       opts.win = true; break;
    case '--mac':       opts.mac = true; break;
    case '--linux':     opts.linux = true; break;
    case '--clean':     opts.clean = true; break;
    case '--build':     opts.build = true; break;
    case '--sign':      opts.sign = true; break;
    case '--upload':    opts.upload = true; break;
    case '--publish':   opts.publish = true; break;
    case '--all':
      opts.clean = opts.build = opts.sign = opts.upload = opts.publish = true;
      break;
    case '--cert':
      opts.cert = args[++i] || '';
      break;
    case '--cert-password':
      opts.certPassword = args[++i] || '';
      break;
    case '--edition':
      opts.edition = args[++i] || 'personal';
      break;
    case '--channel':
      opts.channel = args[++i] || 'stable';
      break;
    case '--version':
      opts.version = args[++i] || '';
      break;
    case '--help':   // fallthrough
    case '-h':
      printHelp();
      process.exit(0);
      break;
    default:
      break;
  }
  i++;
}

// ---------- 校验 ----------

const platformCount = [opts.win, opts.mac, opts.linux].filter(Boolean).length;
if (platformCount !== 1) {
  console.error('错误: 请指定且仅指定一个平台（--win / --mac / --linux）');
  process.exit(1);
}

if (!['personal', 'enterprise'].includes(opts.edition)) {
  console.error('错误: --edition 必须是 personal 或 enterprise');
  process.exit(1);
}

if (!['stable', 'beta', 'alpha'].includes(opts.channel)) {
  console.error('错误: --channel 必须是 stable、beta 或 alpha');
  process.exit(1);
}

// 默认执行 build
if (!opts.clean && !opts.build && !opts.sign && !opts.upload && !opts.publish) {
  opts.build = true;
}

const platform = opts.win ? 'win32' : opts.mac ? 'darwin' : 'linux';
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
const version = opts.version || pkg.version;

// ---------- Git 元数据 ----------

let gitCommit = '';
let gitBranch = '';
try {
  gitCommit = execSync('git rev-parse --short HEAD', { cwd: ROOT, encoding: 'utf-8' }).trim();
  gitBranch = execSync('git rev-parse --abbrev-ref HEAD', { cwd: ROOT, encoding: 'utf-8' }).trim();
} catch {
  // 非 git 环境 — 留空
}

const buildTimestamp = new Date().toISOString();

// ---------- OSS 路径计算 ----------

/**
 * OSS 对象路径前缀：
 * - Beta:  releases/beta/{version}/   （独立生命周期，可设 OSS 自动过期策略）
 * - Alpha: releases/{version}/alpha/  （方案 B：版本优先）
 * - Stable: releases/{version}/       （无渠道后缀，向后兼容现有布局）
 */
function getOssPrefix() {
  if (opts.channel === 'beta') return `releases/beta/${version}`;
  if (opts.channel === 'alpha') return `releases/${version}/alpha`;
  return `releases/${version}`;
}

// electron-builder 输出目录名（与 OSS 路径解耦，加渠道后缀防冲突）
function getReleaseDirName() {
  if (opts.channel === 'stable') return version;
  return `${version}-${opts.channel}`;
}

// ---------- 工具函数 ----------

function run(cmd, args, runOpts = {}) {
  return new Promise((resolve, reject) => {
    const child = spawn(cmd, args, {
      cwd: ROOT,
      stdio: 'inherit',
      shell: true,
      ...runOpts,
      env: { ...process.env, ...(runOpts.env || {}) },
    });
    child.on('close', (code) => {
      if (code === 0) resolve();
      else reject(new Error(`${cmd} ${args.join(' ')} 退出码: ${code}`));
    });
    child.on('error', reject);
  });
}

function runScript(name, ...scriptArgs) {
  const scriptPath = join(SCRIPTS, `${name}.mjs`);
  return run('node', [scriptPath, ...scriptArgs]);
}

function step(title) {
  console.log(`\n${'='.repeat(60)}`);
  console.log(`  ${title}`);
  console.log(`${'='.repeat(60)}\n`);
}

// ---------- 主流程 ----------

async function main() {
  const electronBuilderPlatform = opts.win ? '--win' : opts.mac ? '--mac' : '--linux';
  const editionTag = opts.edition === 'enterprise' ? '企业版' : '个人版';
  const channelTag = opts.channel === 'stable' ? '' : ` · ${opts.channel} 渠道`;
  const ossPrefix = getOssPrefix();
  const releaseDirName = getReleaseDirName();

  console.log('┌──────────────────────────────────────────────┐');
  console.log(`│  HeiXiu 构建 v${version}  ${platform}  ${editionTag}`.padEnd(51) + '│');
  if (channelTag) {
    console.log(`│  ${channelTag.trim()}`.padEnd(51) + '│');
  }
  if (gitCommit) {
    console.log(`│  git: ${gitBranch}@${gitCommit}`.padEnd(51) + '│');
  }
  console.log('└──────────────────────────────────────────────┘');
  console.log(`操作: ${[
    opts.clean && '清理',
    opts.build && '构建',
    opts.sign && '签名',
    opts.upload && '上传',
    opts.publish && '发布',
  ].filter(Boolean).join(' → ')}`);
  console.log(`本地产物: release/${releaseDirName}/`);
  console.log(`OSS 路径: ${ossPrefix}/`);

  // ── Step 0: 构建前校验 ──
  if (opts.build) {
    step('0/ 构建前校验');
    try {
      await runScript('pre-build-check', platform, version, opts.channel);
    } catch (err) {
      console.error(`\n❌ 构建前校验失败: ${err.message}`);
      console.error('如需跳过校验，请使用 --skip-check 参数（或注释 build.mjs 中对应行）');
      process.exit(1);
    }
  }

  // ── Step 1: 清理 ──
  if (opts.clean) {
    step('1/ 清理构建产物');
    await runScript('clean');
  }

  // ── Step 2: 构建 ──
  if (opts.build) {
    step('2/ 构建应用');

    // 签名环境变量
    const signEnv = {};
    if (opts.sign) {
      if (opts.cert) signEnv.CSC_LINK = opts.cert;
      if (opts.certPassword) signEnv.CSC_KEY_PASSWORD = opts.certPassword;
      console.log(opts.cert ? `签名证书: ${opts.cert}` : '签名: 使用系统证书存储');
    }

    // 写入构建元数据
    const metaPath = join(ROOT, 'release', '.build-meta.json');
    const metaDir = join(ROOT, 'release');
    if (!existsSync(metaDir)) mkdirSync(metaDir, { recursive: true });
    writeFileSync(metaPath, JSON.stringify({
      version,
      platform,
      edition: opts.edition,
      channel: opts.channel,
      gitCommit,
      gitBranch,
      buildTimestamp,
      ossPrefix,
      releaseDirName,
    }, null, 2), 'utf-8');

    // 2a. TypeScript 编译
    console.log('[tsc] 类型检查...');
    await run('npx', ['tsc']);

    // 2b. Vite 构建 + 注入构建元数据
    console.log('[vite] 打包前端 + Electron...');
    await run('npx', ['vite', 'build'], {
      env: {
        VITE_BUILD_VERSION: version,
        VITE_BUILD_CHANNEL: opts.channel,
        VITE_BUILD_EDITION: opts.edition,
        VITE_BUILD_COMMIT: gitCommit,
        VITE_BUILD_TIMESTAMP: buildTimestamp,
      },
    });

    // 2c. electron-builder 打包
    console.log(`[electron-builder] ${electronBuilderPlatform} 打包 (${editionTag}${channelTag})...`);
    await run('npx', [
      'electron-builder',
      electronBuilderPlatform,
      '--config', 'build/electron-builder.js',
    ], {
      env: {
        ...signEnv,
        HEIXIU_EDITION: opts.edition,
        HEIXIU_CHANNEL: opts.channel,
        HEIXIU_RELEASE_DIR_NAME: releaseDirName,
      },
    });

    // 2d. 生成 update-info.json
    console.log('[info] 生成 update-info.json...');
    await runScript('generate-update-info', platform, version, opts.channel, opts.edition, ossPrefix, releaseDirName);
  }

  // ── Step 3: 上传 OSS ──
  if (opts.upload) {
    step('3/ 上传 OSS');
    await runScript('upload-oss', platform, version, opts.channel, ossPrefix, releaseDirName);
  }

  // ── Step 4: 发布到 API ──
  if (opts.publish) {
    step('4/ 发布版本到 API');
    await runScript('publish-release', platform, version, opts.channel, opts.edition, ossPrefix, releaseDirName);
  }

  console.log('\n✅ 全部完成');

  // 构建元数据摘要
  console.log(dim(`\n构建摘要:`));
  console.log(dim(`  版本:     ${version}`));
  console.log(dim(`  平台:     ${platform}`));
  console.log(dim(`  版本类型: ${opts.edition}`));
  console.log(dim(`  渠道:     ${opts.channel}`));
  console.log(dim(`  OSS:      ${ossPrefix}/`));
  if (gitCommit) console.log(dim(`  Commit:   ${gitCommit} (${gitBranch})`));
  console.log(dim(`  时间:     ${buildTimestamp}`));
}

// ---------- 帮助 ----------

function printHelp() {
  const box = (title) => {
    const W = 62;
    const pad = Math.max(0, W - 4 - title.length);
    console.log(`\n${cyan('┌')}${cyan('─'.repeat(W - 2))}${cyan('┐')}`);
    console.log(`${cyan('│')}  ${bold(title)}${' '.repeat(pad)}${cyan('│')}`);
    console.log(`${cyan('└')}${cyan('─'.repeat(W - 2))}${cyan('┘')}`);
  };
  const row = (flag, desc) => {
    console.log(`  ${green(flag.padEnd(24))}${dim(desc)}`);
  };
  const hdr = (t) => console.log(`\n  ${bold(yellow(t))}`);

  console.log('');
  console.log(cyan('  ╔') + cyan('═══════════════════════════════════════════════════') + cyan('╗'));
  console.log(cyan('  ║') + bold('   船长·HeiXiu — 构建工具') + '                          ' + cyan('║'));
  console.log(cyan('  ╚') + cyan('═══════════════════════════════════════════════════') + cyan('╝'));

  box('用法');
  console.log(`  ${bold('node build/build.mjs')} ${dim('<平台> [选项...]')}`);
  console.log(`  ${bold('npm run build:win')}    ${dim('— 等效快捷命令')}`);

  hdr('平台（必选其一）');
  row('--win',   'Windows');
  row('--mac',   'macOS');
  row('--linux', 'Linux');

  hdr('版本 & 渠道');
  row('--edition <personal|enterprise>',  '版本类型（默认 personal）');
  row('--channel <stable|beta|alpha>',    '发布渠道（默认 stable）');
  row('--version <x.y.z>',              '覆盖 package.json 版本号');

  hdr('操作（可选组合，不指定则默认 --build）');
  row('--build',   '构建应用（校验 → tsc → vite → electron-builder → info）');
  row('--clean',   '构建前清理 release/ dist/ dist-electron/');
  row('--sign',    '代码签名（需配合 --cert 或环境变量）');
  row('--upload',  '上传安装包 + blockmap 到 OSS');
  row('--publish', 'POST 版本信息到后端 API');
  row('--all',     '全流程 = clean + build + sign + upload + publish');

  hdr('签名参数（配合 --sign）');
  row('--cert <path>',       '证书文件路径（.pfx / .p12）');
  row('--cert-password <p>', '证书密码');
  console.log(`  ${dim('也可通过 CSC_LINK / CSC_KEY_PASSWORD 环境变量设置')}`);

  hdr('灰度发布示例');
  console.log(`  ${dim('# Beta 渠道打包 + 上传 + 发布')}`);
  console.log(`  ${bold('node build/build.mjs --win --channel beta --upload --publish')}`);
  console.log(`  ${dim('# Alpha 渠道仅打包测试')}`);
  console.log(`  ${bold('node build/build.mjs --win --channel alpha')}`);
  console.log(`  ${dim('# 企业版全流程')}`);
  console.log(`  ${bold('node build/build.mjs --win --edition enterprise --all')}`);

  box('OSS 路径规则');
  console.log(`  ${yellow('Stable')}  ${dim('→ releases/{version}/            （向后兼容）')}`);
  console.log(`  ${yellow('Beta')}    ${dim('→ releases/beta/{version}/        （独立生命周期）')}`);
  console.log(`  ${yellow('Alpha')}   ${dim('→ releases/{version}/alpha/       （版本优先）')}`);

  box('npm 快捷命令');
  console.log(`  ${bold('npm run build:win')}              ${dim('→ node build/build.mjs --win')}`);
  console.log(`  ${bold('npm run build:win:enterprise')}    ${dim('→ node build/build.mjs --win --edition enterprise')}`);
  console.log(`  ${bold('npm run build:win:beta')}          ${dim('→ node build/build.mjs --win --channel beta')}`);
  console.log(`  ${bold('npm run build:mac')}              ${dim('→ node build/build.mjs --mac')}`);
  console.log(`  ${bold('npm run build:linux')}            ${dim('→ node build/build.mjs --linux')}`);
  console.log(`  ${bold('npm run build:clean')}            ${dim('→ node build/scripts/clean.mjs')}`);
  console.log(`  ${bold('npm run version:patch')}           ${dim('→ node build/scripts/bump-version.mjs patch')}`);

  box('环境变量');
  console.log(`  ${yellow('UPDATE_API_URL')}         ${dim('版本检查 API 基地址')}`);
  console.log(`  ${yellow('UPDATE_API_KEY')}         ${dim('发布 API 鉴权 Key')}`);
  console.log(`  ${yellow('UPDATE_DOWNLOAD_BASE')}   ${dim('OSS 下载基地址')}`);
  console.log(`  ${yellow('OSS_ENDPOINT')}           ${dim('阿里云 OSS endpoint')}`);
  console.log(`  ${yellow('OSS_BUCKET')}             ${dim('阿里云 OSS bucket')}`);
  console.log(`  ${yellow('OSS_ACCESS_KEY_ID')}      ${dim('阿里云 AccessKey ID')}`);
  console.log(`  ${yellow('OSS_ACCESS_KEY_SECRET')}  ${dim('阿里云 AccessKey Secret')}`);
  console.log(`  ${yellow('CSC_LINK')}               ${dim('签名证书路径')}`);
  console.log(`  ${yellow('CSC_KEY_PASSWORD')}       ${dim('签名证书密码')}`);

  console.log('');
}

// ---------- 入口 ----------

main().catch((err) => {
  console.error(`\n❌ 构建失败: ${err.message}`);
  process.exit(1);
});
