import type { H3Event } from 'h3'
import { eq } from 'drizzle-orm'
import { users } from '../database/schema'
import { getUserApprovedRoleCodes } from './roles'

/**
 * Role validation cache TTL (Time To Live)
 * Roles are re-validated against DB after this period
 */
const ROLE_VALIDATION_TTL = 5 * 60 * 1000 // 5 minutes in milliseconds

/**
 * Get user's active role with automatic validation
 *
 * Features:
 * - Returns cached role from session if TTL hasn't expired
 * - Re-validates against DB after TTL expires (every 5 minutes)
 * - Auto-fallback if active role was revoked by admin
 * - Updates session automatically with validated data
 *
 * @param event - H3 Event from API handler
 * @returns Active role code (e.g., 'private', 'educator', 'company')
 * @throws 401 if user is not authenticated
 */
export async function getUserActiveRole(event: H3Event): Promise<string> {
  const session = await getUserSession(event)

  if (!session?.user) {
    throw createError({
      statusCode: 401,
      message: 'Not authenticated',
    })
  }

  const now = Date.now()
  const lastValidated = session.rolesLastValidated
    ? new Date(session.rolesLastValidated).getTime()
    : 0
  const needsRevalidation = now - lastValidated > ROLE_VALIDATION_TTL

  if (needsRevalidation) {
    // TTL expired → Re-validate against database
    const currentRoles = await getUserApprovedRoleCodes(session.user.id)
    const activeRole = session.activeRoleCode || 'private'

    // Check: Was active role revoked by admin?
    if (!currentRoles.includes(activeRole)) {
      // Auto-fallback to first available role
      const newActiveRole = currentRoles[0] || 'private'

      await replaceUserSession(event, {
        activeRoleCode: newActiveRole,
        userApprovedRoles: currentRoles,
        rolesLastValidated: new Date().toISOString(),
        roleChangedByAdmin: true, // Flag for client notification
      })

      return newActiveRole
    }

    // Role still valid, just update cache + timestamp
    await replaceUserSession(event, {
      userApprovedRoles: currentRoles,
      rolesLastValidated: new Date().toISOString(),
    })
  }

  return session.activeRoleCode || 'private'
}

/**
 * Set user's active role with validation
 *
 * Validates that user has the requested role before switching.
 * Updates both session (immediate) and database (preference for next login).
 *
 * @param event - H3 Event from API handler
 * @param roleCode - Role to switch to (must be in user's approved roles)
 * @throws 401 if not authenticated
 * @throws 403 if user doesn't have the requested role
 */
export async function setUserActiveRole(
  event: H3Event,
  roleCode: string
): Promise<void> {
  const session = await requireUserSession(event)

  // Validate that user has this role
  const approvedRoles = await getUserApprovedRoleCodes(session.user.id)

  if (!approvedRoles.includes(roleCode)) {
    throw createError({
      statusCode: 403,
      message: 'Du hast diese Rolle nicht',
    })
  }

  // Update session with new active role
  await replaceUserSession(event, {
    activeRoleCode: roleCode,
    roleChangedByAdmin: false, // User switched manually
    rolesLastValidated: new Date().toISOString(), // Reset TTL
  })

  // Update database: Save as user preference for next login
  const db = useDatabase()
  await db
    .update(users)
    .set({ lastActiveRoleCode: roleCode })
    .where(eq(users.id, session.user.id))
}
