/**
 * Canonical permission catalog.
 *
 * Source of truth for the permission keys used by:
 *   - RLS policies in Supabase (via has_org_permission(org_id, key))
 *   - API middleware (via requireOrganizationPermission(key))
 *   - UI access checks (via useAccess() permission-backed AccessKeys)
 *
 * The DB table `org_rol_permissions` mirrors this constant. There is no
 * runtime reconciler; parity is enforced two ways:
 *   1. Each migration that adds/removes/modifies a permission must INSERT
 *      (or UPDATE / DELETE) the corresponding `org_rol_permissions` row in
 *      the same transaction.
 *   2. `apps/api/src/auth/multi-tenancy/__tests__/permissions-catalog-sync.integration.test.ts`
 *      asserts the TS catalog and the DB rows agree; CI fails on drift.
 *
 * Adding a permission:
 *   1. Add an entry below.
 *   2. Add a row to the migration (INSERT INTO org_rol_permissions ...) in
 *      the same transaction as any policies/grants that reference the key.
 *   3. Reference it in RLS / middleware as needed.
 *   4. Optionally grant it to one or more system roles in org_rol_grants.
 *
 * Removing a permission: follow the deletion runbook — never just delete
 * the entry. Existing role grants and policy references must be cleared first.
 */

export const PERMISSIONS = {
  ORG_READ: 'org.read',
  ORG_MANAGE: 'org.manage',
  ORG_DELETE: 'org.delete',
  MEMBERS_MANAGE: 'members.manage',
  ROLES_MANAGE: 'roles.manage',
  SECRETS_MANAGE: 'secrets.manage',
  OPERATIONS_READ: 'operations.read',
  OPERATIONS_MANAGE: 'operations.manage',
  SALES_LEAD_GEN_MANAGE: 'sales.lead-gen.manage',
  ACQUISITION_MANAGE: 'acquisition.manage',
  PROJECTS_MANAGE: 'projects.manage',
  CLIENTS_MANAGE: 'clients.manage'
} as const

export type PermissionKey = (typeof PERMISSIONS)[keyof typeof PERMISSIONS]

/**
 * Static metadata for each permission. Mirrored into org_rol_permissions by
 * a migration `INSERT` in the same transaction as any change to this catalog.
 * is_org_grantable=false means the permission is reserved to system roles
 * only — custom roles cannot include it (privilege-escalation guard).
 */
export interface PermissionDescriptor {
  key: PermissionKey
  description: string
  isOrgGrantable: boolean
}

export const PERMISSION_CATALOG: readonly PermissionDescriptor[] = [
  {
    key: 'org.read',
    description: 'Read organization profile and listings',
    isOrgGrantable: true
  },
  {
    key: 'org.manage',
    description: 'Update organization settings',
    isOrgGrantable: false
  },
  {
    key: 'org.delete',
    description: 'Delete the organization (owner-only)',
    isOrgGrantable: false
  },
  {
    key: 'members.manage',
    description: 'Invite, remove, and reassign roles for members',
    isOrgGrantable: false
  },
  {
    key: 'roles.manage',
    description: 'Grant or revoke privileged system roles (owner, admin) within the organization',
    isOrgGrantable: false
  },
  {
    key: 'secrets.manage',
    description: 'Create, update, and delete API keys and credentials',
    isOrgGrantable: false
  },
  {
    key: 'operations.read',
    description: 'View executions, sessions, schedules, and command queue',
    isOrgGrantable: true
  },
  {
    key: 'operations.manage',
    description: 'Run and modify executions, sessions, schedules, queue',
    isOrgGrantable: true
  },
  {
    key: 'sales.lead-gen.manage',
    description: 'Operate Lead Gen lists and list-builder workflows',
    isOrgGrantable: true
  },
  {
    key: 'acquisition.manage',
    description:
      'Create, update, and delete acquisition records (acq_companies, acq_contacts, acq_deals, acq_lists*, acq_content*, acquisition storage files)',
    isOrgGrantable: false
  },
  {
    key: 'projects.manage',
    description: 'Create, update, and delete project records (prj_projects, prj_milestones, prj_tasks, prj_notes)',
    isOrgGrantable: false
  },
  {
    key: 'clients.manage',
    description: 'Create, update, and delete client hub records (clients, clt_* satellites)',
    isOrgGrantable: false
  }
] as const

const PERMISSION_KEY_SET: ReadonlySet<string> = new Set(PERMISSION_CATALOG.map((p) => p.key))

/**
 * Type guard. Use at trust boundaries (request input, third-party data) before
 * passing a string to `has_org_permission` / `requireOrganizationPermission`.
 */
export function isPermissionKey(value: unknown): value is PermissionKey {
  return typeof value === 'string' && PERMISSION_KEY_SET.has(value)
}
