/**
 * 2FA enforcement middleware — auth-2fa.
 *
 * `require2FAIfEnforced()` is chained AFTER authMiddleware and BEFORE
 * requirePermission() on protected routes. It blocks users who are in a
 * tenant where 2FA is enforced but have not yet completed the second factor
 * in this session, except on the bypass endpoint set (BYPASS_2FA_GUARD).
 *
 * Guard order (route handler chain):
 *   authMiddleware → require2FAIfEnforced() → requirePermission() → handler
 */
import type { MiddlewareHandler } from 'hono'
import type { AdminSessionPayload, SessionPayload } from '@zync/types'

type AnySession = SessionPayload | AdminSessionPayload

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

/**
 * Endpoints that are always reachable even while 2FA is required-but-unverified.
 * These must be accessible to unenrolled users in enforcing tenants so they can
 * complete enrollment without first satisfying the guard.
 */
export const BYPASS_2FA_GUARD = new Set([
  'POST /api/auth/2fa/enroll/start',
  'POST /api/auth/2fa/enroll/verify',
  'GET /api/auth/me',
  'POST /api/auth/logout',
])

/**
 * Returns a Hono middleware that enforces 2FA when the active tenant requires it.
 *
 * Pass-through conditions:
 *   - No session (handled upstream by authMiddleware → 401)
 *   - Admin session (type === 'admin')
 *   - User session with no tenant (tid === null)
 *   - Session already verified: two_factor_verified === true
 *   - Tenant does not enforce: enforce_2fa === false
 *   - Request path+method is in BYPASS_2FA_GUARD
 *
 * Blocked condition → 403 { error: '2fa_required', message, setup_url }
 */
export function require2FAIfEnforced(): MiddlewareHandler {
  return async (c, next) => {
    const session = c.get('session') as AnySession | undefined

    // Pass-through: no session, admin session, or tenantless user session
    if (!isUserSession(session) || !session.tid) {
      return next()
    }

    // Pass-through: 2FA not enforced or already verified
    if (!session.enforce_2fa || session.two_factor_verified) {
      return next()
    }

    // Pass-through: bypass endpoint
    const routeKey = `${c.req.method} ${new URL(c.req.url).pathname}`
    if (BYPASS_2FA_GUARD.has(routeKey)) {
      return next()
    }

    // Blocked: enforce_2fa && !two_factor_verified
    return c.json(
      {
        error: '2fa_required',
        message:
          'Your workspace requires two-factor authentication. Please complete 2FA setup to continue.',
        setup_url: '/auth/2fa/setup-required',
      },
      403,
    )
  }
}
