/**
 * Playwright codegen headed 录制 Flock Freight
 * 匿名 get-a-quote + Step 12.78 登录后查价（--logged-in）
 *
 * 用法:
 *   npm run record:flock
 *   npm run record:flock -- list
 *   npm run record:flock -- --logged-in
 *   npm run record:flock -- --logged-in https://app.flockfreight.com/login
 */
import { spawn } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import {
  DEFAULT_FLOCK_DEMO,
  DEFAULT_FLOCK_QUOTE_URL,
  FLOCK_CANONICAL_PATHS,
  formatFlockRecordingChecklist,
} from "@/workers/rpa/flock/demo-input";

const ROOT = process.cwd();
const OUTPUT_DIR = path.join(ROOT, ".rpa", "recordings");

export type FlockRecordMode = "anonymous" | "logged-in";

export type ParsedFlockRecordArgs = {
  mode: FlockRecordMode;
  startUrl?: string;
  pathId?: string;
  help: boolean;
  list: boolean;
  fresh: boolean;
  reuseStorage: boolean;
};

export const ANON_FLOCK_STORAGE_DEFAULT = path.join(
  ROOT,
  ".rpa",
  "flock-storage.json",
);
export const LOGGED_IN_FLOCK_STORAGE_DEFAULT = path.join(
  ROOT,
  ".rpa",
  "flock-logged-in-storage.json",
);

export const DEFAULT_FLOCK_LOGIN_URL =
  process.env.FLOCK_LOGIN_URL?.trim() ||
  "https://app.flockfreight.com/login";

export function parseFlockRecordArgs(argv: string[]): ParsedFlockRecordArgs {
  const tokens = argv.slice(2).filter(Boolean);
  let mode: FlockRecordMode = "anonymous";
  let help = false;
  let list = false;
  let fresh = false;
  let reuseStorage = false;
  let startUrl: string | undefined;
  let pathId: string | undefined;

  for (const token of tokens) {
    if (token === "-h" || token === "--help") {
      help = true;
      continue;
    }
    if (token === "list") {
      list = true;
      continue;
    }
    if (token === "--logged-in" || token === "--login") {
      mode = "logged-in";
      continue;
    }
    if (token === "--fresh") {
      fresh = true;
      continue;
    }
    if (token === "--reuse-storage") {
      reuseStorage = true;
      continue;
    }
    if (token.startsWith("http://") || token.startsWith("https://")) {
      startUrl = token;
      continue;
    }
    if (!token.startsWith("-") && !pathId) {
      pathId = token;
      continue;
    }
  }

  if (process.env.FLOCK_RECORD_FRESH === "true") {
    fresh = true;
  }
  if (process.env.FLOCK_RECORD_REUSE_STORAGE === "true") {
    reuseStorage = true;
  }

  return { mode, startUrl, pathId, help, list, fresh, reuseStorage };
}

export function resolveFlockStoragePath(mode: FlockRecordMode): string {
  if (mode === "logged-in") {
    return (
      process.env.FLOCK_LOGGED_IN_STORAGE_STATE_PATH?.trim() ||
      LOGGED_IN_FLOCK_STORAGE_DEFAULT
    );
  }
  return (
    process.env.FLOCK_STORAGE_STATE_PATH?.trim() || ANON_FLOCK_STORAGE_DEFAULT
  );
}

export function resolveFlockOutputBasename(
  mode: FlockRecordMode,
  ts: string,
  pathId?: string,
): string {
  if (mode === "logged-in") {
    return `flock-logged-in-${ts}.js`;
  }
  const suffix = pathId ?? "manual";
  return `flock-${suffix}-${ts}.js`;
}

export function formatTimestamp(d = new Date()): string {
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
}

export function formatFlockLoggedInRecordingChecklist(): string {
  const demo = DEFAULT_FLOCK_DEMO;
  return [
    "【Flock 登录后查价录制清单】",
    "1. 打开登录页，手动粘贴 FLOCK_LOGIN_EMAIL / FLOCK_LOGIN_PASSWORD 并提交",
    "2. 进入登录后查价入口（记录最终 URL；常见 Let's build a quote / Quick）",
    `3. 标准样例：Pickup ZIP ${demo.pickupZip} → Delivery ZIP ${demo.deliveryZip}`,
    `4. 托盘/重量/尺寸：${demo.palletCount} pallets / ${demo.totalWeightLb} lb / ${demo.lengthIn}×${demo.widthIn}×${demo.heightIn} in`,
    "5. 填 Type / Packaging / Freight Class / Description 等登录后必填项",
    "6. 点 Generate my quote（或等价提交），等到报价结果出现",
    "7. 关闭 codegen，确认 flock-logged-in-*.js + flock-logged-in-storage.json 落盘",
  ].join("\n");
}

function hasFlockEnvCredentials(): boolean {
  const email = process.env.FLOCK_LOGIN_EMAIL?.trim() ?? "";
  const password = process.env.FLOCK_LOGIN_PASSWORD?.trim() ?? "";
  return Boolean(email && password);
}

function printHelp(): void {
  console.log(`
用法:
  npm run record:flock
  npm run record:flock -- list
  npm run record:flock -- <path-id>
  npm run record:flock -- <起始URL>
  npm run record:flock -- --logged-in [起始URL]
  npm run record:flock -- --login [起始URL]

模式:
  匿名（默认）  录制 marketing get-a-quote；可用 --fresh 无痕
  --logged-in   录制账号登录后查价完整路径；storage 与匿名隔离

默认入口:
  匿名: ${DEFAULT_FLOCK_QUOTE_URL}
  登录后: ${DEFAULT_FLOCK_LOGIN_URL}

产出（匿名）:
  .rpa/recordings/flock-<path|manual>-<时间戳>.js
  .rpa/flock-storage.json

产出（登录后）:
  .rpa/recordings/flock-logged-in-<时间戳>.js
  .rpa/flock-logged-in-storage.json

登录后录制说明:
  - 请在 codegen 浏览器中手动粘贴账密（脚本不自动填）
  - SOP: docs/rpa-flock-logged-in-sop.md

标准样例（匿名）:
${formatFlockRecordingChecklist(DEFAULT_FLOCK_DEMO)}

canonical 路径:
${FLOCK_CANONICAL_PATHS.map((p) => `  - ${p.id}: ${p.title}`).join("\n")}
`);
}

function resolveAnonymousStart(
  arg: string | undefined,
): { startUrl: string; pathId?: string; demo: typeof DEFAULT_FLOCK_DEMO } {
  if (!arg) {
    return { startUrl: DEFAULT_FLOCK_QUOTE_URL, demo: DEFAULT_FLOCK_DEMO };
  }
  if (arg.startsWith("http://") || arg.startsWith("https://")) {
    return { startUrl: arg, demo: DEFAULT_FLOCK_DEMO };
  }
  const canonical = FLOCK_CANONICAL_PATHS.find((p) => p.id === arg);
  if (canonical) {
    console.log(`\n路径: ${canonical.id} — ${canonical.title}`);
    console.log(`说明: ${canonical.notes}\n`);
    console.log(formatFlockRecordingChecklist(canonical.input));
    console.log("");
    return {
      startUrl: DEFAULT_FLOCK_QUOTE_URL,
      pathId: canonical.id,
      demo: canonical.input,
    };
  }
  console.warn(`未知 path-id「${arg}」，使用默认样例`);
  return { startUrl: DEFAULT_FLOCK_QUOTE_URL, demo: DEFAULT_FLOCK_DEMO };
}

function main(): void {
  const parsed = parseFlockRecordArgs(process.argv);

  if (parsed.help) {
    printHelp();
    process.exit(0);
  }

  if (parsed.list) {
    console.log("Flock canonical 录制路径:\n");
    for (const p of FLOCK_CANONICAL_PATHS) {
      console.log(`  ${p.id}`);
      console.log(`    ${p.title}`);
      console.log(`    ${p.notes}\n`);
    }
    process.exit(0);
  }

  const mode = parsed.mode;
  const storagePath = resolveFlockStoragePath(mode);
  const ts = formatTimestamp();

  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  fs.mkdirSync(path.dirname(storagePath), { recursive: true });

  let startUrl: string;
  let pathId: string | undefined;
  let demo = DEFAULT_FLOCK_DEMO;
  let checklistBody: string;

  if (mode === "logged-in") {
    startUrl = parsed.startUrl ?? DEFAULT_FLOCK_LOGIN_URL;
    checklistBody = formatFlockLoggedInRecordingChecklist();
  } else {
    const resolved = resolveAnonymousStart(parsed.startUrl ?? parsed.pathId);
    startUrl = resolved.startUrl;
    pathId = resolved.pathId;
    demo = resolved.demo;
    checklistBody = formatFlockRecordingChecklist(demo);
  }

  const outputFile = path.join(
    OUTPUT_DIR,
    resolveFlockOutputBasename(mode, ts, pathId),
  );
  const checklistFile = outputFile.replace(/\.js$/, ".checklist.txt");
  fs.writeFileSync(checklistFile, checklistBody, "utf8");

  const args = [
    "playwright",
    "codegen",
    "--target=javascript",
    "-o",
    outputFile,
  ];

  if (mode === "logged-in") {
    // 登录态必须持久 session，禁止 --fresh 跳过 save
    args.push(`--save-storage=${storagePath}`);
    if (fs.existsSync(storagePath)) {
      args.push(`--load-storage=${storagePath}`);
      console.log(`已加载已有 storageState: ${storagePath}`);
    }
  } else if (parsed.fresh) {
    console.log("【无痕录制 --fresh】不加载/保存 storage");
  } else if (parsed.reuseStorage) {
    args.push(`--save-storage=${storagePath}`);
    if (fs.existsSync(storagePath)) {
      args.push(`--load-storage=${storagePath}`);
      console.log(`已加载已有 storageState: ${storagePath}`);
    }
  } else {
    args.push(`--save-storage=${storagePath}`);
    console.log(`录制结束将保存 storage: ${storagePath}`);
    console.log("若已达报价上限，请使用: npm run record:flock -- --fresh");
  }

  args.push(startUrl);

  if (mode === "logged-in") {
    console.log("=== Flock Freight 登录后查价录制（headed）===");
    console.log("RPA_HEADLESS=false");
    console.log("模式: --logged-in（storage 与匿名 flock-storage.json 隔离）");
    if (hasFlockEnvCredentials()) {
      console.log(
        "已检测到 .env 中 FLOCK_LOGIN_EMAIL/PASSWORD：请在浏览器中手动粘贴登录（脚本不自动填）",
      );
    } else {
      console.log(
        "未检测到 FLOCK_LOGIN_EMAIL/PASSWORD：请用管理端客户账密或准备官网账号后手动登录",
      );
    }
    console.log(`起始 URL: ${startUrl}`);
    console.log(`脚本产出: ${outputFile}`);
    console.log(`清单文件: ${checklistFile}`);
    console.log(`storageState: ${storagePath}`);
    console.log("SOP: docs/rpa-flock-logged-in-sop.md");
  } else {
    console.log("=== Flock Freight RPA 录制（headed / 匿名）===");
    console.log("RPA_HEADLESS=false");
    console.log(`起始 URL: ${startUrl}`);
    console.log(`脚本产出: ${outputFile}`);
    console.log(`清单文件: ${checklistFile}`);
    console.log(`storageState: ${storagePath}`);
    console.log("登录后请用: npm run record:flock -- --logged-in");
  }
  console.log("");
  console.log(checklistBody);
  console.log("");

  const child = spawn("npx", args, {
    stdio: "inherit",
    shell: true,
    cwd: ROOT,
    env: { ...process.env, RPA_HEADLESS: "false" },
  });

  child.on("error", (error) => {
    console.error("启动 playwright codegen 失败:", error);
    process.exit(1);
  });

  child.on("exit", (code) => {
    if (code === 0) {
      if (mode === "logged-in") {
        console.log(
          "\n录制结束。请回填 docs/rpa-flock-logged-in-sop.md 附录 A；可运行: npx tsx scripts/finalize-flock-logged-in-recording.ts",
        );
      } else {
        console.log(
          "\n录制结束。请将 flock-*.js 中的 selector 填入 .env FLOCK_SELECTOR_*",
        );
      }
    }
    process.exit(code ?? 0);
  });
}

// vitest 导入本模块时勿启动 codegen
const isRecordEntrypoint = /record-flock\.(ts|js|mjs|cjs)$/.test(
  process.argv[1] ?? "",
);
if (isRecordEntrypoint && !process.env.VITEST && !process.env.VITEST_WORKER_ID) {
  main();
}
