import { PGlite } from '@electric-sql/pglite'
import { drizzle } from 'drizzle-orm/pglite'
import { eq } from 'drizzle-orm'
import { pgTable, text, uuid } from 'drizzle-orm/pg-core'
import { describe, expect, it } from 'vitest'
import {
  createTriadRbac,
  permissionsTable,
  rolesTable,
  SYSTEM_ROLE_NAMES,
  SYSTEM_ROLE_PERMISSIONS,
  triadSchema,
} from './rbac-triad.js'

type TriadSchema = typeof triadSchema

const TENANT_ID = '00000000-0000-4000-8000-000000000010'

async function createTriadDb() {
  const client = new PGlite()
  const db = drizzle(client, { schema: triadSchema })
  await client.exec(`
    CREATE TABLE tenancy_permissions (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      key text NOT NULL UNIQUE
    );
    CREATE TABLE tenancy_roles (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
      tenant_id uuid NOT NULL,
      name text NOT NULL,
      is_system_role boolean NOT NULL DEFAULT false
    );
    CREATE TABLE tenancy_role_permissions (
      role_id uuid NOT NULL REFERENCES tenancy_roles(id) ON DELETE CASCADE,
      permission_id uuid NOT NULL REFERENCES tenancy_permissions(id) ON DELETE CASCADE,
      PRIMARY KEY (role_id, permission_id)
    );
  `)
  return db
}

describe('createTriadRbac', () => {
  it('resolves seeded ADMIN permissions for an active membership roleKey', async () => {
    const db = await createTriadDb()
    const rbac = createTriadRbac(db)
    await rbac.seedPermissionCatalog()
    await rbac.seedSystemRoles(TENANT_ID)

    const caps = await rbac.resolveCapabilities({
      userId: 'user-1',
      tenantId: TENANT_ID,
      roleKey: 'ADMIN',
    })

    expect(caps.sort()).toEqual([...SYSTEM_ROLE_PERMISSIONS.ADMIN].sort())
    expect(caps).not.toContain('billing:manage')
  })

  it('returns [] for unknown roleKey (fail-closed)', async () => {
    const db = await createTriadDb()
    const rbac = createTriadRbac(db)
    await rbac.seedPermissionCatalog()
    await rbac.seedSystemRoles(TENANT_ID)

    await expect(
      rbac.resolveCapabilities({
        userId: 'user-1',
        tenantId: TENANT_ID,
        roleKey: 'NOT_A_ROLE',
      }),
    ).resolves.toEqual([])
  })

  it('resolves a custom per-tenant role permission set', async () => {
    const db = await createTriadDb()
    const rbac = createTriadRbac(db)
    await rbac.seedPermissionCatalog()

    const [role] = await db
      .insert(rolesTable)
      .values({ tenantId: TENANT_ID, name: 'CUSTOM', isSystemRole: false })
      .returning()

    const [perm] = await db
      .select({ id: permissionsTable.id })
      .from(permissionsTable)
      .where(eq(permissionsTable.key, 'reports:read'))
      .limit(1)

    await db.insert(triadSchema.rolePermissions).values({
      roleId: role!.id,
      permissionId: perm!.id,
    })

    const caps = await rbac.resolveCapabilities({
      userId: 'user-1',
      tenantId: TENANT_ID,
      roleKey: 'CUSTOM',
    })
    expect(caps).toEqual(['reports:read'])
  })
})

describe('SYSTEM_ROLE_NAMES', () => {
  it('matches the production system role set (spec excludes ACCOUNTANT)', () => {
    expect([...SYSTEM_ROLE_NAMES]).toEqual([
      'OWNER',
      'ADMIN',
      'MEMBER',
      'VIEWER',
      'CONTRACTOR',
    ])
  })
})
