import { describe, expect, it } from 'vitest'

import {
  assertTenantOwnsOrThrow,
  assertTenantOwnsProject,
  InvalidTenantReferenceError,
} from '../../../../../../packages/db/src/queries/tenant-guards'
import { projects } from '../../../../../../packages/db/src/schema/projects'
import { createPlatformTenancyStore, syncPlatformTenancyRbac } from '../tenancy'

const TENANT_A = 'tenant-a'
const USER_A = 'user-a'

function tableName(table: unknown): string {
  const candidate = table as { _?: { config?: { name?: string } } } | null | undefined
  const symbolName = (candidate as Record<symbol, unknown> | null | undefined)?.[Symbol.for('drizzle:Name')]
  return typeof symbolName === 'string' ? symbolName : candidate?._?.config?.name ?? 'unknown'
}

function createSelectMock(resolvers: Record<string, () => unknown[]>) {
  return () => ({
    from(table: unknown) {
      const run = resolvers[tableName(table)] ?? (() => [])
      const builder = {
        innerJoin() {
          return builder
        },
        where() {
          return builder
        },
        limit() {
          return Promise.resolve(run())
        },
        then(resolve: (value: unknown[]) => unknown, reject?: (reason: unknown) => unknown) {
          return Promise.resolve(run()).then(resolve, reject)
        },
      }
      return builder
    },
  })
}

describe('tenancy platform parity', () => {
  it('keeps field-permission RBAC split while syncing only the embedded triad tables', async () => {
    const insertTargets: string[] = []
    const executed: unknown[] = []
    const db = {
      insert(table: unknown) {
        insertTargets.push(tableName(table))
        return {
          values() {
            return {
              onConflictDoNothing: async () => [],
            }
          },
        }
      },
      execute(statement: unknown) {
        executed.push(statement)
        return Promise.resolve([])
      },
    }

    await syncPlatformTenancyRbac(db as never, TENANT_A)

    expect(insertTargets.length).toBeGreaterThan(0)
    expect(new Set(insertTargets)).toEqual(new Set(['tenancy_permissions']))
    expect(executed).toHaveLength(3)
  })

  it('enumerates tenants and memberships faithfully through the TenancyStore surface', async () => {
    const db = {
      select: createSelectMock({
        tenants: () => [
          {
            id: TENANT_A,
            slug: 'alpha',
            name: 'Alpha',
            settings: {},
            createdAt: new Date('2026-07-01T00:00:00Z'),
          },
        ],
        roles: () => [{ id: 'role-admin' }],
        tenant_memberships: (() => {
          let calls = 0
          return () => {
            calls += 1
            if (calls === 1) return [{ userId: USER_A }]
            if (calls === 2) {
              return [
                { tenantId: TENANT_A, userId: USER_A, roleKey: 'OWNER', status: 'active' },
                { tenantId: TENANT_A, userId: 'user-b', roleKey: 'ADMIN', status: 'active' },
              ]
            }
            return [{ tenantId: TENANT_A, userId: 'user-b', roleKey: 'ADMIN', status: 'active' }]
          }
        })(),
      }),
      insert() {
        return {
          values() {
            return {
              onConflictDoNothing: async () => [],
              onConflictDoUpdate: async () => [],
            }
          },
        }
      },
      update() {
        return {
          set() {
            return {
              where: async () => [],
            }
          },
        }
      },
      delete() {
        return {
          where: async () => [],
        }
      },
      execute() {
        return Promise.resolve([
          {
            id: TENANT_A,
            slug: 'alpha',
            name: 'Alpha',
            settings: { suspended: true },
            createdAt: new Date('2026-07-01T00:00:00Z'),
          },
        ])
      },
    }

    const store = createPlatformTenancyStore(db as never)

    expect(await store.getTenantBySlug('alpha')).toMatchObject({
      id: TENANT_A,
      ownerId: USER_A,
      status: 'active',
    })

    await store.addMember({
      tenantId: TENANT_A,
      userId: 'user-b',
      roleKey: 'ADMIN',
      status: 'active',
    })

    expect(await store.listMembers(TENANT_A)).toEqual([
      { tenantId: TENANT_A, userId: USER_A, roleKey: 'OWNER', status: 'active' },
      { tenantId: TENANT_A, userId: 'user-b', roleKey: 'ADMIN', status: 'active' },
    ])

    expect(await store.suspendTenant(TENANT_A)).toMatchObject({
      id: TENANT_A,
      status: 'suspended',
    })
  })

  it('matches the host ownership verdict and denies forged cross-tenant project access', async () => {
    let calls = 0
    const db = {
      select: () => ({
        from(table: unknown) {
          expect(table).toBe(projects)
          const builder = {
            where() {
              return builder
            },
            limit() {
              calls += 1
              return Promise.resolve(calls === 1 ? [{ id: 'project-a' }] : [])
            },
          }
          return builder
        },
      }),
    }

    await expect(assertTenantOwnsProject(db as never, TENANT_A, 'project-a')).resolves.toBe(true)
    await expect(assertTenantOwnsProject(db as never, TENANT_A, 'project-b')).resolves.toBe(false)
    expect(() => assertTenantOwnsOrThrow('projectId', false)).toThrow(InvalidTenantReferenceError)
  })
})
