/**
 * RBAC seed helpers — foundation-auth-rbac.
 *  - seedPermissions(db): idempotent upsert of every permission key.
 *  - seedSystemRoles(db, tenantId): on tenant creation, insert the 5 system
 *    roles and wire role_permissions per the default matrix.
 */
import { and, eq, inArray } from 'drizzle-orm'
import type { Db } from '../client'
import { permissions, roles, rolePermissions } from '../schema'
import {
  PERMISSION_KEYS,
  SYSTEM_ROLE_NAMES,
  SYSTEM_ROLE_PERMISSIONS,
  type SystemRoleName,
} from '../seed/permission-keys'

/**
 * Idempotent: re-running inserts zero duplicates (ON CONFLICT (key) DO NOTHING).
 * Returns the count of permission rows now present for the seeded keys.
 */
export async function seedPermissions(db: Db): Promise<number> {
  await db
    .insert(permissions)
    .values(PERMISSION_KEYS.map((key) => ({ key })))
    .onConflictDoNothing({ target: permissions.key })

  const rows = await db
    .select({ id: permissions.id })
    .from(permissions)
    .where(inArray(permissions.key, [...PERMISSION_KEYS]))
  return rows.length
}

/**
 * Seed the 5 system roles for a freshly created tenant and wire their default
 * permissions. Assumes seedPermissions(db) has already populated `permissions`.
 * Idempotent on the (tenant_id, name) unique constraint and the
 * role_permissions composite PK.
 */
export async function seedSystemRoles(db: Db, tenantId: string): Promise<void> {
  // 1. Insert the 5 system roles (idempotent on UNIQUE(tenant_id, name)).
  await db
    .insert(roles)
    .values(SYSTEM_ROLE_NAMES.map((name) => ({ tenantId, name, isSystemRole: true })))
    .onConflictDoNothing({ target: [roles.tenantId, roles.name] })

  // 2. Resolve THIS tenant's role ids (scoped to tenantId) and a perm-key -> id map.
  const roleRows = await db
    .select({ id: roles.id, name: roles.name })
    .from(roles)
    .where(and(eq(roles.tenantId, tenantId), inArray(roles.name, [...SYSTEM_ROLE_NAMES])))
  const roleIdByName = new Map<string, string>()
  for (const r of roleRows) roleIdByName.set(r.name, r.id)

  const permRows = await db
    .select({ id: permissions.id, key: permissions.key })
    .from(permissions)
    .where(inArray(permissions.key, [...PERMISSION_KEYS]))
  const permIdByKey = new Map(permRows.map((p) => [p.key, p.id]))

  // 3. Build role_permissions rows from the default matrix.
  const links: { roleId: string; permissionId: string }[] = []
  for (const roleName of SYSTEM_ROLE_NAMES) {
    const roleId = roleIdByName.get(roleName)
    if (!roleId) continue
    for (const key of SYSTEM_ROLE_PERMISSIONS[roleName as SystemRoleName]) {
      const permissionId = permIdByKey.get(key)
      if (permissionId) links.push({ roleId, permissionId })
    }
  }

  if (links.length > 0) {
    await db
      .insert(rolePermissions)
      .values(links)
      .onConflictDoNothing({ target: [rolePermissions.roleId, rolePermissions.permissionId] })
  }
}
