/**
 * deploy.mjs — 依具名目標部署 console-ui 到 Cloudflare Pages
 *
 * 用法：npm run deploy:personal
 *       npm run deploy:personal -- --dry-run   （只產出並驗產物，不推）
 *
 * 為什麼不直接用 `wrangler pages deploy`（2026-07-22 leo 立，實際踩到才補）：
 *   **兩個帳號都有名為 arcrun-console-ui 的 Pages 專案**
 *   wrangler 若 OAuth 登入在別的帳號，`--project-name arcrun-console-ui` 會部到別人的站上。
 *   本腳本強制帶目標的 accountId，並在部署前印出目標，避免部錯帳號。
 *
 *   同時把 profile/apiBase 綁進目標（deploy.targets.json），不再靠部署者記得帶環境變數——
 *   帶漏過三次：漏 profile 顯示成錯的版本、漏 apiBase 導致登入 405。
 *
 * 🔴 三道閘，全部**讀磁碟上真的要被推的那份**，不看本腳本自己印了什麼
 *    （2026-08-08 事故的形狀正是「印的是 A、推的是 B」）：
 *      ① 產物閘   ：宣告值有沒有真的寫進產物（apiBase / VIEWS / HOME）
 *      ② 世代閘   ：產物是不是當代（指紋＋t160 的文字指紋）
 *      ③ 線上閘   ：推完回頭抓線上，組態＋世代都要對上，否則本次部署算失敗
 *    三閘都過才寫 .deploy-state.json（那份紀錄是「經過線上實測」的意思，不是「我跑過指令」）。
 */
import { spawnSync } from 'node:child_process';
import { join } from 'node:path';
import { ROOT, assertArtifact, buildArtifact, loadTargets, resolveTarget, writeState } from './targets.mjs';
import { printReport, verifyTarget } from './verify-live.mjs';

const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const name = args.find((a) => !a.startsWith('--'));

let t;
try {
  if (!name) throw Object.assign(new Error('沒有指定部署目標'), { usage: true });
  t = resolveTarget(name);
} catch (e) {
  console.error(`✘ ${e.message}`);
  if (e.usage) console.error(`用法：npm run deploy:<target>\n可用目標：${loadTargets().active.join(' / ')}`);
  process.exit(1);
}

if (t.frozen) {
  console.error(`✘ 目標 ${name} 已凍結，拒絕部署。\n  ${t.frozen}`);
  console.error('  （要解凍是人的決定：改 deploy.targets.json 拿掉 frozen 欄位，並說明理由。）');
  process.exit(1);
}

console.log(`\n部署目標：${name}`);
console.log(`  說明    ：${t.description}`);
console.log(`  帳號    ：${t.accountId}`);
console.log(`  專案    ：${t.projectName}`);
console.log(`  profile ：${t.profile}`);
console.log(`  apiBase ：${t.apiBase}`);

// ── ①② 產出 + 驗產物 ────────────────────────────────────────────────
const outDir = join(ROOT, '.staging', name);
try {
  buildArtifact(t, outDir);
} catch (e) {
  console.error(`\n✘ 產出失敗：${e.message}`);
  process.exit(1);
}

const gate = assertArtifact(t, outDir);
console.log(`\n產物：${outDir}`);
console.log(`  世代指紋：${gate.generation.slice(0, 12)}`);
if (!gate.ok) {
  console.error('\n✘ 產物閘不通過——推上去的會跟宣告的不一樣，拒絕部署：');
  for (const p of gate.problems) console.error(`    · ${p}`);
  process.exit(1);
}
console.log('  ✅ 產物閘：宣告值確實寫進產物，且是當代。');

if (dryRun) {
  console.log('\n（--dry-run：到此為止，沒有推任何東西。）');
  process.exit(0);
}

// ── 推 ───────────────────────────────────────────────────────────────
const env = { ...process.env, DEPLOY_TARGET: name, CLOUDFLARE_ACCOUNT_ID: t.accountId };
// --commit-dirty：本地部署常有未提交變更，不因此中斷
const deploy = spawnSync(
  'npx',
  ['wrangler', 'pages', 'deploy', outDir, '--project-name', t.projectName, '--commit-dirty=true'],
  { stdio: 'inherit', cwd: ROOT, env },
);
if (deploy.status !== 0) {
  console.error('\n✘ wrangler 部署失敗。');
  process.exit(deploy.status ?? 1);
}

// ── ③ 線上閘 ─────────────────────────────────────────────────────────
console.log('\n── 回頭驗線上（組態＋世代）──');
const report = await verifyTarget(name, { wait: true });
printReport([report]);
if (!report.ok) {
  console.error('\n✘ 推上去了，但線上跑的 ≠ 我們手上這一份。**本次部署視為失敗**。');
  console.error('   （wrangler 說成功不代表對外網址就對——這正是要被擋掉的那個病。）');
  process.exit(1);
}

writeState(name, {
  generation: gate.generation,
  apiBase: t.apiBase,
  profile: t.profile,
  urls: t.verifyUrls,
  verifiedAt: new Date().toISOString(),
});
console.log('\n✅ 部署完成，且線上實測＝宣告值＋當代世代。已記入 .deploy-state.json。');
