import { eq, sql } from 'drizzle-orm'
import type { MiddlewareHandler } from 'hono'
import { describe, expect, it, vi } from 'vitest'

import { createPgliteClient } from '../../../../packages/db/src/postgres/pglite.ts'
import { createApp } from '../../src/index.js'
import { createSubscribeRoute } from '../../src/routes/subscribe.js'
import {
  accounts,
  entitlementTierGrants,
  entitlements,
  plugins,
  pressZoneInitSql,
  pressZoneSchema,
  subscriptionPackages,
  subscriptions,
  walletBalances,
} from '../../src/schema.js'

type TestDb = ReturnType<typeof createPgliteClient<typeof pressZoneSchema>>

async function createTestDb(): Promise<TestDb> {
  const db = createPgliteClient({ schema: pressZoneSchema })

  for (const statement of pressZoneInitSql.split(';').map((part) => part.trim()).filter(Boolean)) {
    await db.execute(sql.raw(statement))
  }

  return db
}

async function readJson(response: Response): Promise<unknown> {
  return response.json()
}

function createProtectedMiddleware(accountId: string): MiddlewareHandler {
  return async (context, next) => {
    context.set('principal', {
      account: accountId,
      userId: 'user-subscribe',
      scopes: [],
    })
    context.set('capabilities', [])
    await next()
  }
}

describe('HTTP integration: subscribe flow', () => {
  it('creates the subscription, grants the tier, and seeds the wallet via the mounted app path', async () => {
    const db = await createTestDb()
    const accountId = '00000000-0000-0000-0000-000000000111'

    await db.insert(accounts).values({
      id: accountId,
      slug: 'acct-subscribe',
    })
    await db.insert(plugins).values({
      key: 'translate',
      name: 'Translate',
      permissionCatalog: ['plugin:translate'],
    })
    await db.insert(subscriptionPackages).values({
      pluginKey: 'translate',
      tierKey: 'pro',
      currency: 'USD',
      priceMinor: 1_900n,
      creditAllocation: 100n,
      seatsConfig: 5,
      paypalPlanId: 'plan_translate_pro',
    })
    await db.insert(entitlementTierGrants).values([
      {
        capability: 'plugin:translate',
        tier: 'pro',
        quotaKey: '',
        quotaValue: null,
      },
      {
        capability: 'plugin:translate',
        tier: 'pro',
        quotaKey: 'translate:chars',
        quotaValue: 100,
      },
    ])

    const createSubscription = vi.fn(async () => ({
      id: 'I-SUB-HTTP-1',
      status: 'ACTIVE',
      currentPeriod: '2026-07',
      planId: 'plan_translate_pro',
    }))
    const app = createApp({
      subscribeRoute: createSubscribeRoute({
        db,
        provider: { createSubscription },
      }),
      protectedMiddleware: createProtectedMiddleware(accountId),
    })

    const response = await app.request('http://press-zone.test/api/subscribe', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({
        pluginKey: 'translate',
        tierKey: 'pro',
      }),
    })

    expect(response.status).toBe(200)
    await expect(readJson(response)).resolves.toEqual({
      data: {
        accountId,
        pluginKey: 'translate',
        tierKey: 'pro',
        status: 'ACTIVE',
        paypalSubscriptionId: 'I-SUB-HTTP-1',
        currentPeriod: '2026-07',
        walletKey: `${accountId}:translate:2026-07`,
      },
    })
    expect(createSubscription).toHaveBeenCalledWith({
      idempotencyKey: `subscribe:${accountId}:translate:pro`,
      planId: 'plan_translate_pro',
      currentPeriod: '2026-07',
    })

    const subscriptionRows = await db.select().from(subscriptions)
    expect(subscriptionRows).toHaveLength(1)

    const entitlementRows = await db
      .select()
      .from(entitlements)
      .where(eq(entitlements.account, accountId))
    expect(entitlementRows.length).toBeGreaterThan(0)

    const [wallet] = await db
      .select({ balance: walletBalances.balance })
      .from(walletBalances)
      .where(eq(walletBalances.ownerId, `${accountId}:translate:2026-07`))
      .limit(1)
    expect(wallet?.balance).toBe(100n)
  })
})
