/**
 * page-helpers.ts — 页面与权限管理的共享 DB 操作原语
 *
 * 接受 PrismaClient 作为参数，可被 CLI 脚本（page-manage.ts / permission-manage.ts）
 * 和 seed/*.seed.ts（含 data-mngt.seed.ts）共同调用。
 */

import { PrismaClient } from '@prisma/client';

export const FULL_ACTIONS = ['createAny', 'readAny', 'updateAny', 'deleteAny'];

// ─── Resource ─────────────────────────────────────────────────────────────────

/**
 * Upsert a Resource row.
 * update: {} preserves any manual edits on re-run.
 */
export async function upsertResource(
  prisma: PrismaClient,
  code: string,
  description = `${code} resource`,
) {
  return prisma.resource.upsert({
    where: { code },
    update: {},
    create: { code, name: code, description, isCommonResource: false },
  });
}

// ─── Page ─────────────────────────────────────────────────────────────────────

export interface PageDef {
  code: string;
  name: string;
  zhName?: string;
  enName?: string;
  sortOrder?: number;
  parentId?: number;
  isVirtual?: boolean;
  /** Only applied on create — update: {} preserves user edits */
  path?: string;
}

/**
 * Upsert a Page row.
 * update: {} on the default call so manual DB edits are preserved.
 * Pass updateData to selectively sync specific fields (e.g. path).
 */
export async function upsertPage(
  prisma: PrismaClient,
  def: PageDef,
  updateData: Record<string, unknown> = {},
) {
  return prisma.page.upsert({
    where: { code: def.code },
    update: updateData,
    create: {
      code: def.code,
      name: def.name,
      zhName: def.zhName ?? def.name,
      enName: def.enName ?? def.name,
      isVirtual: def.isVirtual ?? false,
      sortOrder: def.sortOrder ?? 9999,
      ...(def.parentId !== undefined && { parentId: def.parentId }),
      ...(def.path !== undefined && { path: def.path }),
    },
  });
}

// ─── PageResource ─────────────────────────────────────────────────────────────

/**
 * Upsert a Resource then link it to a page via PageResource.
 * Idempotent — safe to re-run.
 */
export async function bindResourceToPage(
  prisma: PrismaClient,
  pageId: number,
  code: string,
  description?: string,
) {
  const resource = await upsertResource(
    prisma,
    code,
    description ?? `${code} resource`,
  );
  await prisma.pageResource.upsert({
    where: { pageId_resourceId: { pageId, resourceId: resource.id } },
    update: { actions: FULL_ACTIONS },
    create: { pageId, resourceId: resource.id, actions: FULL_ACTIONS },
  });
  return resource;
}

// ─── Role access ──────────────────────────────────────────────────────────────

/**
 * Grant a role access to a page + its linked resources.
 * Upserts RolePages and one RoleResource per resource.
 */
export async function grantRoleAccess(
  prisma: PrismaClient,
  roleId: number,
  pageId: number,
  resourceIds: number[],
) {
  await prisma.rolePages.upsert({
    where: { roleId_pageId: { roleId, pageId } },
    update: {},
    create: { roleId, pageId },
  });

  for (const resourceId of resourceIds) {
    await prisma.roleResource.upsert({
      where: { roleId_resourceId: { roleId, resourceId } },
      update: { actions: FULL_ACTIONS },
      create: { roleId, resourceId, actions: FULL_ACTIONS },
    });
  }
}

/**
 * Revoke a role's access to a page + its linked resources.
 * Deletes RolePages and RoleResource rows.
 */
export async function revokeRoleAccess(
  prisma: PrismaClient,
  roleId: number,
  pageId: number,
  resourceIds: number[],
) {
  await prisma.rolePages.deleteMany({ where: { roleId, pageId } });

  for (const resourceId of resourceIds) {
    await prisma.roleResource.deleteMany({ where: { roleId, resourceId } });
  }
}

// ─── Convenience: get resource IDs linked to a page ──────────────────────────

export async function getPageResourceIds(
  prisma: PrismaClient,
  pageId: number,
): Promise<number[]> {
  const rows = await prisma.pageResource.findMany({
    where: { pageId },
    select: { resourceId: true },
  });
  return rows.map((r) => r.resourceId);
}

export async function getPageResources(prisma: PrismaClient, pageId: number) {
  return prisma.pageResource.findMany({
    where: { pageId },
    include: { resource: { select: { id: true, code: true } } },
  });
}
