/**
 * Host Admin CLI — PAC 团队管理 host 的本地命令行(取代 HTTP write endpoint)。
 *
 * 设计:敏感写操作(create / rotate / deactivate)**只走 CLI**,SSH 到 PAC 生产服务器 +
 * DB 直连即可,不需要 web 鉴权 / 不需要 PAC 内部用户系统。读操作仍走 HTTP /admin/hosts。
 *
 * 安全模型:
 *   - 谁能跑:SSH 到 PAC 服务器 + 有 DATABASE_URL 访问权(物理隔离)
 *   - Plaintext 密钥:CLI 输出 stdout,运维即看即存 1Password,不入日志(走 stderr 防重定向)
 *   - 审计:SSH 登录日志 + DB binlog;后续可扩 pac_admin_actions 审计表
 *
 * 跑:
 *   pnpm pac:host create --name=friday --push
 *   pnpm pac:host list
 *   pnpm pac:host get <id-or-name>
 *   pnpm pac:host rotate-secret <id-or-name>
 *   pnpm pac:host rotate-push <id-or-name>
 *   pnpm pac:host deactivate <id-or-name>
 */
import { NestFactory } from '@nestjs/core';
import { Logger } from '@nestjs/common';
import { AppModule } from '../app.module';
import { HostsService } from '../modules/admin/hosts.service';

interface ParsedArgs {
  command: string;
  positional: string[];
  flags: Record<string, string | boolean>;
}

function parseArgs(argv: string[]): ParsedArgs {
  const command = argv[0] ?? '';
  const rest = argv.slice(1);
  const positional: string[] = [];
  const flags: Record<string, string | boolean> = {};
  for (const a of rest) {
    if (a.startsWith('--')) {
      const eq = a.indexOf('=');
      if (eq > -1) flags[a.slice(2, eq)] = a.slice(eq + 1);
      else flags[a.slice(2)] = true;
    } else {
      positional.push(a);
    }
  }
  return { command, positional, flags };
}

function printHelp() {
  // eslint-disable-next-line no-console
  console.log(`
PAC Host Admin CLI

Usage:
  pnpm pac:host <command> [args] [--flags]

Commands:
  create --name=<slug> [--push] [--amount-unit=yuan|fen] [--timezone=Asia/Shanghai]
                              注册新 host。返回 appId + appSecret + pushSecret(plaintext 一次性)
  list                        列出所有 host 摘要
  get <id-or-name>            查看一个 host 详情
  rotate-secret <id-or-name>  轮换 appSecret(旧立即失效)
  rotate-push <id-or-name>    轮换 pushSecret(数组前插,grace 期共存)
  deactivate <id-or-name>     软停 host(后续 auth 拒绝)

Examples:
  pnpm pac:host create --name=friday --push --amount-unit=yuan --timezone=Asia/Shanghai
  pnpm pac:host list
  pnpm pac:host rotate-secret friday
  pnpm pac:host deactivate friday
`);
}

async function resolveHostId(
  svc: HostsService,
  idOrName: string,
): Promise<string> {
  // 是 UUID 形态直接返;否则按 name 查
  if (/^[0-9a-f]{8}-[0-9a-f]{4}/.test(idOrName)) return idOrName;
  const list = await svc.list();
  const found = list.items.find((p) => p.name === idOrName);
  if (!found) throw new Error(`host not found by name="${idOrName}"`);
  return found.id;
}

async function main() {
  const args = parseArgs(process.argv.slice(2));
  if (!args.command || args.command === 'help' || args.command === '--help') {
    printHelp();
    process.exit(0);
  }

  const logger = new Logger('pac:host');
  const app = await NestFactory.createApplicationContext(AppModule, {
    logger: ['warn', 'error'],
  });

  try {
    const svc = app.get(HostsService);

    switch (args.command) {
      case 'create': {
        const name = args.flags.name as string | undefined;
        if (!name) {
          // eslint-disable-next-line no-console
          console.error('  --name=<slug> is required');
          process.exit(2);
        }
        const pushEnabled = !!args.flags.push;
        const amountUnit = (args.flags['amount-unit'] as 'fen' | 'yuan' | undefined) ?? 'yuan';
        const timezone = (args.flags['timezone'] as string | undefined) ?? 'Asia/Shanghai';

        const result = await svc.create({
          name,
          pushEnabled,
          pullConfig: {
            endpoints: {},
            amountUnit,
            timezone,
            intervalMinutes: 5,
          },
        });

        // 输出到 stderr,避免被 stdout 重定向到日志文件
        // eslint-disable-next-line no-console
        console.error(`
✓ Created host "${result.name}"
  id:        ${result.id}
  appId:     ${result.appId}
  appSecret: ${result.appSecret}
  pushSecret: ${result.pushSecret ?? '(push not enabled)'}
  active:    ${result.active}

⚠️  立即把 appSecret / pushSecret 存到 1Password 共享空间 "PAC-Production/${result.name}",
   PAC 不再保留 plaintext,失落只能 rotate。
`);
        break;
      }

      case 'list': {
        const result = await svc.list();
        // eslint-disable-next-line no-console
        console.log(`\n  ${result.items.length} host(s):\n`);
        for (const p of result.items) {
          // eslint-disable-next-line no-console
          console.log(
            `    ${p.name.padEnd(20)} appId=${p.appId.padEnd(28)} push_keys=${p.pushKeyCount} active=${p.active}  id=${p.id}`,
          );
        }
        // eslint-disable-next-line no-console
        console.log('');
        break;
      }

      case 'get': {
        const idOrName = args.positional[0];
        if (!idOrName) {
          // eslint-disable-next-line no-console
          console.error('  usage: pnpm pac:host get <id-or-name>');
          process.exit(2);
        }
        const id = await resolveHostId(svc, idOrName);
        const p = await svc.get(id);
        // eslint-disable-next-line no-console
        console.log(JSON.stringify(p, null, 2));
        break;
      }

      case 'rotate-secret': {
        const idOrName = args.positional[0];
        if (!idOrName) {
          // eslint-disable-next-line no-console
          console.error('  usage: pnpm pac:host rotate-secret <id-or-name>');
          process.exit(2);
        }
        const id = await resolveHostId(svc, idOrName);
        const r = await svc.rotateAppSecret(id);
        // eslint-disable-next-line no-console
        console.error(`
✓ Rotated appSecret for host id=${id}
  new appSecret: ${r.appSecret}

⚠️  立即同步给 host backend,旧 appSecret 已**立即失效**。
`);
        break;
      }

      case 'rotate-push': {
        const idOrName = args.positional[0];
        if (!idOrName) {
          // eslint-disable-next-line no-console
          console.error('  usage: pnpm pac:host rotate-push <id-or-name>');
          process.exit(2);
        }
        const id = await resolveHostId(svc, idOrName);
        const r = await svc.rotatePushSecret(id);
        // eslint-disable-next-line no-console
        console.error(`
✓ Rotated pushSecret for host id=${id}
  new pushSecret: ${r.pushSecret}
  total active keys (含 grace 旧 key): ${r.totalKeys}

⚠️  数组前插 — 旧 pushSecret 仍接受,grace 期共存。
   host 切换到新 key 后,运维清理旧 key 通过单独 DB 脚本(本期不暴露专用 CLI)。
`);
        break;
      }

      case 'deactivate': {
        const idOrName = args.positional[0];
        if (!idOrName) {
          // eslint-disable-next-line no-console
          console.error('  usage: pnpm pac:host deactivate <id-or-name>');
          process.exit(2);
        }
        const id = await resolveHostId(svc, idOrName);
        await svc.deactivate(id);
        // eslint-disable-next-line no-console
        console.error(`✓ Deactivated host ${id} (auth 立即拒绝)`);
        break;
      }

      default:
        // eslint-disable-next-line no-console
        console.error(`Unknown command "${args.command}"`);
        printHelp();
        process.exit(2);
    }
  } catch (err) {
    logger.error(err instanceof Error ? err.stack ?? err.message : String(err));
    process.exitCode = 2;
  } finally {
    await app.close();
  }
}

main().catch((err) => {
  // eslint-disable-next-line no-console
  console.error(err);
  process.exit(3);
});
