import { PGlite } from '@electric-sql/pglite'
import { and, asc, eq } from 'drizzle-orm'
import { drizzle } from 'drizzle-orm/pglite'
import type { TransactionalDatabase } from '@platform-modules/db'
import { entitlementTierGrants, entitlements, entitlementsSchema } from './schema.js'

type TestClockDb = { __entitlementsNow?: () => Date }

export type TestDb = TransactionalDatabase<typeof entitlementsSchema> & TestClockDb

export async function createTestDb(): Promise<TestDb> {
  const client = new PGlite()
  const db = drizzle(client, { schema: entitlementsSchema }) as unknown as TestDb

  await client.exec(`
    CREATE TABLE entitlements (
      account text NOT NULL,
      capability text NOT NULL,
      tier text NOT NULL,
      granted_at timestamptz NOT NULL,
      expires_at timestamptz,
      PRIMARY KEY (account, capability)
    );
    CREATE TABLE entitlement_tier_grants (
      capability text NOT NULL,
      tier text NOT NULL,
      quota_key text NOT NULL DEFAULT '',
      quota_value integer,
      PRIMARY KEY (capability, tier, quota_key)
    );
  `)

  return db
}

export function setTestNow(db: TestDb, now: Date): void {
  db.__entitlementsNow = () => now
}

export async function seedGrant(
  db: TestDb,
  input: {
    account: string
    feature: string
    tier: string
    grantedAt?: Date
    expiresAt?: Date | null
  },
): Promise<void> {
  await db.insert(entitlements).values({
    account: input.account,
    capability: input.feature,
    tier: input.tier,
    grantedAt: input.grantedAt ?? new Date('2026-07-03T00:00:00.000Z'),
    expiresAt: input.expiresAt ?? null,
  })
}

export async function seedTierGrant(
  db: TestDb,
  input: {
    capability: string
    tier: string
    quotaKey?: string | null
    quotaValue?: number | null
  },
): Promise<void> {
  await db.insert(entitlementTierGrants).values({
    capability: input.capability,
    tier: input.tier,
    quotaKey: input.quotaKey ?? '',
    quotaValue: input.quotaValue ?? null,
  })
}

export async function getGrant(
  db: TestDb,
  account: string,
  feature: string,
): Promise<(typeof entitlements.$inferSelect) | undefined> {
  const [row] = await db
    .select()
    .from(entitlements)
    .where(and(eq(entitlements.account, account), eq(entitlements.capability, feature)))
    .limit(1)
  return row
}

export async function listGrants(accountDb: TestDb, account: string) {
  return accountDb
    .select()
    .from(entitlements)
    .where(eq(entitlements.account, account))
    .orderBy(asc(entitlements.capability))
}
