/**
 * permission-manage.ts — 角色页面权限管理
 *
 * Usage:
 *
 *   ── 授予角色访问页面的权限 ───────────────────────────────────────────────────
 *   ts-node scripts/permission-manage.ts grant \
 *     --pageCode  myModule                (required)
 *     --roles     SYSTEM_ADMIN,MY_ROLE    (optional, defaults to SYSTEM_ADMIN)
 *
 *   ── 撤销角色访问页面的权限 ───────────────────────────────────────────────────
 *   ts-node scripts/permission-manage.ts revoke \
 *     --pageCode  myModule                (required)
 *     --roles     MY_ROLE                 (required)
 *
 * grant 行为：
 *   1. Upsert Role
 *   2. Upsert RolePages（role ↔ page）
 *   3. Upsert RoleResource（role ↔ 该页面的每个关联资源）
 *
 * revoke 行为：
 *   1. 删除 RolePages（role ↔ page）
 *   2. 删除 RoleResource（role ↔ 该页面的每个关联资源）
 *
 * Prerequisites: run page-manage.ts first to ensure the page + resources exist.
 */

import { PrismaClient } from '@prisma/client';
import {
  getPageResources,
  grantRoleAccess,
  revokeRoleAccess,
} from './lib/page-helpers';

const prisma = new PrismaClient();

// ─── Arg parser ───────────────────────────────────────────────────────────────

function parseArgs(): { action: string; flags: Record<string, string> } {
  const argv = process.argv.slice(2);
  const action = argv[0] && !argv[0].startsWith('--') ? argv[0] : '';
  const flags: Record<string, string> = {};
  for (let i = action ? 1 : 0; i < argv.length; i++) {
    if (argv[i].startsWith('--')) {
      const key = argv[i].slice(2);
      const next = argv[i + 1];
      flags[key] = next && !next.startsWith('--') ? argv[++i] : 'true';
    }
  }
  return { action, flags };
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

async function requirePage(pageCode: string) {
  const page = await prisma.page.findUnique({ where: { code: pageCode } });
  if (!page) {
    console.error(
      `[permission-manage] Page "${pageCode}" not found in DB. Run page-manage.ts create first.`,
    );
    process.exit(1);
  }
  return page;
}

// ─── Actions ──────────────────────────────────────────────────────────────────

async function actionGrant(flags: Record<string, string>) {
  const { pageCode, roles } = flags;
  if (!pageCode) {
    console.error('[permission-manage] --pageCode is required.');
    process.exit(1);
  }

  const roleNames = roles
    ? roles
        .split(',')
        .map((s) => s.trim())
        .filter(Boolean)
    : ['SYSTEM_ADMIN'];

  const page = await requirePage(pageCode);
  const pageResources = await getPageResources(prisma, page.id);

  if (pageResources.length === 0) {
    console.warn(
      `[permission-manage] ⚠ No resources linked to page "${pageCode}". Bind resources first via page-manage.ts bind.`,
    );
  } else {
    console.log(
      `[permission-manage] Resources: [${pageResources
        .map((pr) => pr.resource.code)
        .join(', ')}]`,
    );
  }

  const resourceIds = pageResources.map((pr) => pr.resource.id);

  for (const roleName of roleNames) {
    const role = await prisma.role.upsert({
      where: { name: roleName },
      update: {},
      create: { name: roleName, description: `${roleName} role` },
    });
    console.log(`[permission-manage] Role: ${roleName} (id=${role.id})`);

    await grantRoleAccess(prisma, role.id, page.id, resourceIds);
    console.log(`[permission-manage]   RolePages: ${roleName} → ${pageCode}`);
    for (const pr of pageResources) {
      console.log(
        `[permission-manage]   RoleResource: ${roleName} → ${pr.resource.code}`,
      );
    }
  }
}

async function actionRevoke(flags: Record<string, string>) {
  const { pageCode, roles } = flags;
  if (!pageCode) {
    console.error('[permission-manage] --pageCode is required.');
    process.exit(1);
  }
  if (!roles) {
    console.error('[permission-manage] --roles is required.');
    process.exit(1);
  }

  const roleNames = roles
    .split(',')
    .map((s) => s.trim())
    .filter(Boolean);
  const page = await requirePage(pageCode);
  const pageResources = await getPageResources(prisma, page.id);
  const resourceIds = pageResources.map((pr) => pr.resource.id);

  for (const roleName of roleNames) {
    const role = await prisma.role.findUnique({ where: { name: roleName } });
    if (!role) {
      console.warn(
        `[permission-manage] Role "${roleName}" not found — skipped`,
      );
      continue;
    }

    await revokeRoleAccess(prisma, role.id, page.id, resourceIds);
    console.log(
      `[permission-manage] Revoked RolePages: ${roleName} → ${pageCode}`,
    );
    for (const pr of pageResources) {
      console.log(
        `[permission-manage]   Revoked RoleResource: ${roleName} → ${pr.resource.code}`,
      );
    }
  }
}

// ─── Entry point ──────────────────────────────────────────────────────────────

const ACTIONS: Record<string, (f: Record<string, string>) => Promise<void>> = {
  grant: actionGrant,
  revoke: actionRevoke,
};

async function main() {
  const { action, flags } = parseArgs();
  const handler = ACTIONS[action];
  if (!handler) {
    console.error(
      `[permission-manage] Unknown action: "${action}". Valid actions: ${Object.keys(
        ACTIONS,
      ).join(', ')}`,
    );
    process.exit(1);
  }
  await handler(flags);
  console.log('[permission-manage] ✅ Done.');
}

main()
  .catch((e) => {
    console.error('[permission-manage] Fatal error:', e);
    process.exit(1);
  })
  .finally(() => prisma.$disconnect());
