/**
 * GET  /api/admin/oauth/clients       — list OAuth clients (wave-12)
 * POST /api/admin/oauth/clients       — register new OAuth client
 * PATCH /api/admin/oauth/clients/:id  — update client
 *
 * Protected by requireAdminSession (admin-only).
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { hashToken } from '@zync/auth'
import {
  createDb,
  listOAuthClientsQuery,
  createOAuthClientRecord,
  updateOAuthClientRecord,
} from '@zync/db/queries'
import type { AppEnv } from '../../types'

const createClientSchema = z.object({
  clientId: z.string().min(1),
  clientSecret: z.string().min(1),
  name: z.string().min(1),
  redirectUris: z.array(z.string().url()).default([]),
  scopes: z.array(z.string()).default([]),
  isFirstParty: z.boolean().optional().default(false),
  logoUrl: z.string().url().nullable().optional(),
})

const updateClientSchema = z.object({
  redirectUris: z.array(z.string().url()).optional(),
  scopes: z.array(z.string()).optional(),
  name: z.string().min(1).optional(),
  logoUrl: z.string().url().nullable().optional(),
  isFirstParty: z.boolean().optional(),
})

const adminOAuthClientsRoute = new Hono<AppEnv>()

adminOAuthClientsRoute.get('/', async (c) => {
  const db = createDb(c.env)
  const clients = await listOAuthClientsQuery(db)
  // Never return the secret hash
  return c.json({
    clients: clients.map(({ clientSecretHash: _, ...rest }) => rest),
  })
})

adminOAuthClientsRoute.post('/', async (c) => {
  const parsed = createClientSchema.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'invalid_request', error_description: 'clientId, clientSecret, and name are required' }, 400)
  }

  const body = parsed.data
  const secretHash = await hashToken(body.clientSecret)
  const db = createDb(c.env)

  const client = await createOAuthClientRecord(db, {
    clientId: body.clientId,
    clientSecretHash: secretHash,
    name: body.name,
    redirectUris: body.redirectUris,
    scopes: body.scopes,
    isFirstParty: body.isFirstParty ?? false,
    logoUrl: body.logoUrl ?? null,
  })

  const { clientSecretHash: _, ...clientOut } = client
  return c.json({ client: clientOut }, 201)
})

adminOAuthClientsRoute.patch('/:id', async (c) => {
  const { id } = c.req.param()
  const parsed = updateClientSchema.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'invalid_request', error_description: 'Invalid request body' }, 400)
  }

  const body = parsed.data
  const db = createDb(c.env)
  const updated = await updateOAuthClientRecord(db, id, {
    ...(body.redirectUris !== undefined && { redirectUris: body.redirectUris }),
    ...(body.scopes !== undefined && { scopes: body.scopes }),
    ...(body.name !== undefined && { name: body.name }),
    ...(body.logoUrl !== undefined && { logoUrl: body.logoUrl }),
    ...(body.isFirstParty !== undefined && { isFirstParty: body.isFirstParty }),
  })

  if (!updated) return c.json({ error: 'not_found' }, 404)

  const { clientSecretHash: _, ...clientOut } = updated
  return c.json({ client: clientOut })
})

export { adminOAuthClientsRoute }
