import { Hono } from 'hono'
import { z } from 'zod'
import { generateOpaqueToken, hashPassword, hashToken, timingSafeEqual } from '@zync/auth'
import {
  cleanupE2eRoleFixture,
  createDb,
  E2eFixtureConflictError,
  provisionE2eRoleFixture,
} from '@zync/db/queries'
import type { AppEnv } from '../types'
import { withDoHash } from '../lib/password-hash-do'

const runIdSchema = z.string().min(2).max(64).regex(/^[a-z0-9][a-z0-9-]*$/)
const provisionSchema = z.object({ runId: runIdSchema }).strict()
type FixtureBindings = AppEnv['Bindings'] & {
  ENVIRONMENT?: string
  E2E_FIXTURE_SECRET?: string
}

export const e2eRoleFixturesRoute = new Hono<AppEnv>()

e2eRoleFixturesRoute.use('*', async (c, next) => {
  const env = c.env as FixtureBindings
  if (env.ENVIRONMENT !== 'preview') return c.notFound()

  const presented = c.req.header('x-e2e-fixture-secret') ?? ''
  const expected = env.E2E_FIXTURE_SECRET ?? ''
  const secretsMatch = presented && expected
    ? timingSafeEqual(await hashToken(presented), await hashToken(expected))
    : false
  if (!secretsMatch) {
    return c.json({ error: 'Forbidden' }, 403)
  }
  c.header('Cache-Control', 'no-store')
  await next()
})

e2eRoleFixturesRoute.post('/', async (c) => {
  const parsed = provisionSchema.safeParse(await c.req.json().catch(() => null))
  if (!parsed.success) return c.json({ error: 'Invalid request' }, 400)

  const password = generateOpaqueToken()
  const passwordHash = await hashPassword(password, withDoHash(c.env))
  try {
    const fixture = await provisionE2eRoleFixture(createDb(c.env), {
      runId: parsed.data.runId,
      passwordHash,
    })
    return c.json({
      runId: parsed.data.runId,
      tenantId: fixture.tenantId,
      tenantSlug: fixture.tenantSlug,
      users: fixture.users.map((user) => ({ ...user, password })),
    }, 201)
  } catch (error) {
    if (error instanceof E2eFixtureConflictError) {
      return c.json({ error: error.message }, 409)
    }
    throw error
  }
})

e2eRoleFixturesRoute.delete('/:runId', async (c) => {
  const parsed = runIdSchema.safeParse(c.req.param('runId'))
  if (!parsed.success) return c.json({ error: 'Invalid request' }, 400)

  const removed = await cleanupE2eRoleFixture(createDb(c.env), parsed.data)
  if (!removed) return c.json({ error: 'Fixture not found' }, 404)
  return c.body(null, 204)
})
