/**
 * Hono RBAC / tier / admin guards — foundation-auth-rbac.
 *
 * These read the verified session that the app's `authMiddleware`
 * (apps/zync-api) has already set on `c.get('session')`. They do NOT verify
 * JWTs themselves — that is the app middleware's job. Mount these AFTER it.
 */
import type { MiddlewareHandler } from 'hono'
import { TenantTier } from '@zync/types'
import type { AdminSessionPayload, SessionPayload } from '@zync/types'
import { meetsMinimumTier } from './entitlements'

type AnySession = SessionPayload | AdminSessionPayload

/** Hono Variables contract these guards depend on. */
export type AuthVariables = {
  session: AnySession
}

function isUserSession(s: AnySession | undefined): s is SessionPayload {
  return !!s && s.type === 'user'
}

function isAdminSession(s: AnySession | undefined): s is AdminSessionPayload {
  return !!s && s.type === 'admin'
}

/**
 * 403 unless the current user session's expanded permission set contains
 * `permission`. 401 if there is no session at all.
 */
export function requirePermission(permission: string): MiddlewareHandler {
  return async (c, next) => {
    const session = c.get('session') as AnySession | undefined
    if (!session) {
      return c.json({ error: 'Unauthorized' }, 401)
    }
    if (!isUserSession(session) || !session.permissions.includes(permission)) {
      return c.json({ error: 'Forbidden', requiredPermission: permission }, 403)
    }
    await next()
  }
}

/**
 * 401 unless the session is an admin session with TOTP already verified.
 * Admin routes are API (JSON), not browser redirects.
 */
export function requireAdminSession(): MiddlewareHandler {
  return async (c, next) => {
    const session = c.get('session') as AnySession | undefined
    if (!isAdminSession(session) || session.totp_verified !== true) {
      return c.json({ error: 'Admin authentication required' }, 401)
    }
    await next()
  }
}

/**
 * 402 `{ error: 'Upgrade required', requiredTier }` unless the active tenant's
 * tier meets `minimum`. Requires a user session with a tier.
 */
export function requireTier(minimum: TenantTier): MiddlewareHandler {
  return async (c, next) => {
    const session = c.get('session') as AnySession | undefined
    if (!isUserSession(session)) {
      return c.json({ error: 'Unauthorized' }, 401)
    }
    if (!meetsMinimumTier(session.tier, minimum)) {
      return c.json({ error: 'Upgrade required', requiredTier: minimum }, 402)
    }
    await next()
  }
}
