/**
 * 打包前置构建脚本
 * 在 electron-builder 打包前：
 *   1. 编译 shared + Node 服务端
 *   2. 确保 Python 依赖就绪
 *   3. 将所有服务端资源复制到 client/build/server-bundle/
 *   4. 复制 Playwright 浏览器到 client/build/playwright-browsers/
 *
 * 使用方式: node scripts/build-server.js
 */

const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');

const ROOT = path.resolve(__dirname, '..', '..');
const CLIENT_DIR = path.resolve(__dirname, '..');
const SERVER_DIR = path.join(ROOT, 'server');
const PYTHON_DIR = path.join(SERVER_DIR, 'python');
const SHARED_DIR = path.join(ROOT, 'shared');

const BUNDLE_DIR = path.join(CLIENT_DIR, '_bundle');
const SERVER_BUNDLE = path.join(BUNDLE_DIR, 'server');
const SHARED_BUNDLE = path.join(BUNDLE_DIR, 'shared');
const PLAYWRIGHT_DEST = path.join(BUNDLE_DIR, 'playwright');

const isWin = process.platform === 'win32';

function run(cmd, cwd) {
  console.log(`\n> [${path.basename(cwd)}] ${cmd}`);
  execSync(cmd, { cwd, stdio: 'inherit', shell: true });
}

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

function cleanDir(dir) {
  if (fs.existsSync(dir)) {
    fs.rmSync(dir, { recursive: true, force: true });
  }
  fs.mkdirSync(dir, { recursive: true });
}

function copyDir(src, dest, options = {}) {
  const { filter, dereference = true } = options;
  if (!fs.existsSync(src)) {
    console.log(`    跳过（不存在）: ${src}`);
    return;
  }
  fs.mkdirSync(dest, { recursive: true });

  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
    const srcPath = path.join(src, entry.name);
    const destPath = path.join(dest, entry.name);

    // 解析可能的 symlink
    let stat;
    try {
      stat = dereference ? fs.statSync(srcPath) : fs.lstatSync(srcPath);
    } catch {
      continue;
    }

    if (stat.isDirectory()) {
      if (filter && filter.skipDir && filter.skipDir(entry.name, srcPath)) continue;
      copyDir(srcPath, destPath, options);
    } else if (stat.isFile()) {
      if (filter && filter.skipFile && filter.skipFile(entry.name, srcPath)) continue;
      fs.copyFileSync(srcPath, destPath);
    }
  }
}

function copyFile(src, dest) {
  if (!fs.existsSync(src)) {
    console.log(`    跳过（不存在）: ${src}`);
    return;
  }
  fs.mkdirSync(path.dirname(dest), { recursive: true });
  fs.copyFileSync(src, dest);
}

function dirSizeMB(dir) {
  try {
    const out = execSync(
      isWin
        ? `powershell -c "(Get-ChildItem -Recurse '${dir}' -File | Measure-Object -Property Length -Sum).Sum"`
        : `du -sb "${dir}" | cut -f1`,
      { encoding: 'utf-8', shell: true }
    ).trim();
    return Math.round(parseInt(out || '0') / 1024 / 1024);
  } catch {
    return -1;
  }
}

// =========================================================
// 1. 编译 shared 包
// =========================================================
step('1/7  编译 shared 包');
if (fs.existsSync(path.join(SHARED_DIR, 'package.json'))) {
  run('npm run build', SHARED_DIR);
} else {
  console.log('  跳过（shared 目录不存在）');
}

// =========================================================
// 2. 编译 Node 服务端
// =========================================================
step('2/7  编译 Node 服务端');
try {
  run('npx tsc', SERVER_DIR);
} catch {
  const distDir = path.join(SERVER_DIR, 'dist');
  if (fs.existsSync(distDir) && fs.readdirSync(distDir).length > 0) {
    console.log('  ⚠ tsc 有类型警告，但 dist/ 已生成，继续');
  } else {
    throw new Error('Node 服务端编译失败且 dist/ 未生成');
  }
}

// =========================================================
// 3. 检查 Python venv
// =========================================================
step('3/7  检查 Python 虚拟环境');
const venvPython = isWin
  ? path.join(PYTHON_DIR, 'venv', 'Scripts', 'python.exe')
  : path.join(PYTHON_DIR, 'venv', 'bin', 'python');

if (fs.existsSync(venvPython)) {
  console.log(`  venv 已存在: ${venvPython}`);
  const reqTxt = path.join(PYTHON_DIR, 'requirements.txt');
  if (fs.existsSync(reqTxt)) {
    console.log('  安装/更新 Python 依赖...');
    run(`"${venvPython}" -m pip install -r requirements.txt --quiet`, PYTHON_DIR);
  }
} else {
  console.log('  venv 不存在，尝试创建...');
  try {
    run(`${isWin ? 'python' : 'python3'} -m venv venv`, PYTHON_DIR);
    const reqTxt = path.join(PYTHON_DIR, 'requirements.txt');
    if (fs.existsSync(reqTxt)) {
      run(`"${venvPython}" -m pip install -r requirements.txt`, PYTHON_DIR);
    }
  } catch (e) {
    console.warn(`  ⚠ 创建 venv 失败: ${e.message}`);
  }
}

if (fs.existsSync(venvPython)) {
  console.log('  确保 Playwright chromium 已安装...');
  try {
    run(`"${venvPython}" -m playwright install chromium`, PYTHON_DIR);
  } catch (e) {
    console.warn(`  ⚠ Playwright install 失败: ${e.message}`);
  }
}

// =========================================================
// 4. 复制 shared 包（server 依赖它，必须先准备好）
// =========================================================
step('4/7  复制 shared 包');
cleanDir(SHARED_BUNDLE);
copyDir(path.join(SHARED_DIR, 'dist'), path.join(SHARED_BUNDLE, 'dist'));
copyFile(path.join(SHARED_DIR, 'package.json'), path.join(SHARED_BUNDLE, 'package.json'));
console.log('  shared 包已就绪');

// =========================================================
// 5. 复制服务端资源 + 安装依赖
// =========================================================
step('5/7  复制服务端资源并安装依赖');

cleanDir(SERVER_BUNDLE);

// 5a. 先复制 package.json 并修改 workspace 引用
console.log('  复制 package.json ...');
copyFile(path.join(SERVER_DIR, 'package.json'), path.join(SERVER_BUNDLE, 'package.json'));

const bundlePkgPath = path.join(SERVER_BUNDLE, 'package.json');
const bundlePkg = JSON.parse(fs.readFileSync(bundlePkgPath, 'utf-8'));
if (bundlePkg.dependencies && bundlePkg.dependencies['@media-manager/shared']) {
  bundlePkg.dependencies['@media-manager/shared'] = 'file:../shared';
  fs.writeFileSync(bundlePkgPath, JSON.stringify(bundlePkg, null, 2), 'utf-8');
  console.log('    -> @media-manager/shared: workspace:* => file:../shared');
}

// 5b. npm install 生成干净的 node_modules（避免 pnpm symlink 问题）
console.log('  运行 npm install --omit=dev (耐心等待) ...');
run('npm install --omit=dev', SERVER_BUNDLE);
console.log(`    -> node_modules: ${dirSizeMB(path.join(SERVER_BUNDLE, 'node_modules'))} MB`);

// 5c. 复制编译后的代码
console.log('  复制 server/dist/ ...');
copyDir(path.join(SERVER_DIR, 'dist'), path.join(SERVER_BUNDLE, 'dist'));
console.log(`    -> dist: ${dirSizeMB(path.join(SERVER_BUNDLE, 'dist'))} MB`);

// 5d. 复制 .env
console.log('  复制 .env ...');
copyFile(path.join(SERVER_DIR, '.env'), path.join(SERVER_BUNDLE, '.env'));

// 5e. 创建 uploads 目录
fs.mkdirSync(path.join(SERVER_BUNDLE, 'uploads'), { recursive: true });
const gitkeep = path.join(SERVER_DIR, 'uploads', '.gitkeep');
if (fs.existsSync(gitkeep)) {
  fs.copyFileSync(gitkeep, path.join(SERVER_BUNDLE, 'uploads', '.gitkeep'));
}

// 5f. 复制 Python 服务（源码 + venv）
console.log('  复制 server/python/ ...');
copyDir(
  PYTHON_DIR,
  path.join(SERVER_BUNDLE, 'python'),
  {
    dereference: true,
    filter: {
      skipDir: (name) => name === '__pycache__' || name === '.pytest_cache',
      skipFile: (name) => name.endsWith('.pyc'),
    },
  }
);
console.log(`    -> python: ${dirSizeMB(path.join(SERVER_BUNDLE, 'python'))} MB`);

// =========================================================
// 6. 复制 Playwright 浏览器
// =========================================================
step('6/7  复制 Playwright 浏览器');

function findPlaywrightBrowsersDir() {
  if (process.env.PLAYWRIGHT_BROWSERS_PATH && fs.existsSync(process.env.PLAYWRIGHT_BROWSERS_PATH)) {
    return process.env.PLAYWRIGHT_BROWSERS_PATH;
  }
  const candidates = [];
  if (isWin) {
    candidates.push(path.join(process.env.LOCALAPPDATA || '', 'ms-playwright'));
  } else if (process.platform === 'darwin') {
    candidates.push(path.join(process.env.HOME || '', 'Library', 'Caches', 'ms-playwright'));
  } else {
    candidates.push(path.join(process.env.HOME || '', '.cache', 'ms-playwright'));
  }
  for (const c of candidates) {
    if (c && fs.existsSync(c)) return c;
  }
  return null;
}

const pwBrowsersDir = findPlaywrightBrowsersDir();
if (!pwBrowsersDir) {
  console.error('  ⚠ 未找到 Playwright 浏览器缓存目录');
} else {
  cleanDir(PLAYWRIGHT_DEST);
  const entries = fs.readdirSync(pwBrowsersDir);
  const needed = entries.filter(n => n.startsWith('chromium') || n.startsWith('ffmpeg'));
  if (needed.length === 0) {
    console.error('  ⚠ 未找到 chromium');
  } else {
    for (const dir of needed) {
      console.log(`  复制 ${dir} ...`);
      copyDir(path.join(pwBrowsersDir, dir), path.join(PLAYWRIGHT_DEST, dir));
      console.log(`    -> ${dirSizeMB(path.join(PLAYWRIGHT_DEST, dir))} MB`);
    }
  }
}

// =========================================================
step('7/7  验证打包资源');

function verify(label, p) {
  const exists = fs.existsSync(p);
  const icon = exists ? '✓' : '✗';
  console.log(`  ${icon} ${label}: ${p} (${exists ? '存在' : '不存在!'})`);
  if (!exists) {
    console.error(`    ⚠ 缺少关键资源，打包后服务将无法启动！`);
  }
}

verify('server dist/app.js', path.join(SERVER_BUNDLE, 'dist', 'app.js'));
verify('server node_modules/', path.join(SERVER_BUNDLE, 'node_modules'));
verify('server .env', path.join(SERVER_BUNDLE, '.env'));
verify('server python/app.py', path.join(SERVER_BUNDLE, 'python', 'app.py'));
verify('shared dist/', path.join(SHARED_BUNDLE, 'dist'));
verify('playwright/', PLAYWRIGHT_DEST);

step('构建完成！所有资源已准备就绪');
console.log(`  server:     ${SERVER_BUNDLE}`);
console.log(`  shared:     ${SHARED_BUNDLE}`);
console.log(`  playwright: ${PLAYWRIGHT_DEST}`);
