import type { MiddlewareHandler } from 'hono'
import { verifyAdminSession } from '@zync/auth'
import { createDb, findAdminWithPermissions } from '@zync/db/queries'
import type { AdminAppSession, AppEnv } from '../types'
import { getAdminOrigins } from '../lib/origins'
import { ADMIN_COOKIE } from '../lib/cookies'

const MUTATING = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])

function parseAdminCookie(cookieHeader: string | null | undefined): string | null {
  if (!cookieHeader) return null
  for (const part of cookieHeader.split(';')) {
    const eq = part.indexOf('=')
    if (eq === -1) continue
    if (part.slice(0, eq).trim() === ADMIN_COOKIE) {
      return decodeURIComponent(part.slice(eq + 1).trim())
    }
  }
  return null
}

export const adminAuthMiddleware: MiddlewareHandler<AppEnv> = async (c, next) => {
  if (MUTATING.has(c.req.method)) {
    const origin = c.req.header('Origin')
    const allowedOrigins = getAdminOrigins({
      environment: (c.env as { ENVIRONMENT?: string } | undefined)?.ENVIRONMENT,
    })
    if (!origin || !allowedOrigins.has(origin)) {
      return c.json({ error: 'Forbidden: invalid Origin' }, 403)
    }
  }

  const db = createDb(c.env)
  c.set('db', db)

  const token = parseAdminCookie(c.req.header('Cookie'))
  if (!token) return c.json({ error: 'Unauthorized' }, 401)

  try {
    const session = await verifyAdminSession(token, c.env.JWT_SECRET)
    // Load permissions from DB so requireAdminPermission() works.
    const admin = await findAdminWithPermissions(db, session.sub)
    const nextSession: AdminAppSession = {
      ...session,
      permissions: admin?.permissions ?? [],
      ...(admin?.role ? { role: admin.role } : {}),
    }
    c.set('session', nextSession)
  } catch {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  await next()
}
