import { type H3Event, createError, getCookie } from 'h3'
import type { AuthSession } from '../types/api.ts'
import { useDB, eq } from './database.ts'
import { resolveSession } from './session-resolver.ts'
import { user as userTable } from '../database/schema/auth.ts'

// Re-export getAuth and auth type from auth-instance to maintain backwards compatibility
export { getAuth, type auth } from '../lib/auth-instance.ts'

/**
 * Enhance a Better Auth session with custom logic:
 * - Handle impersonation (if admin is impersonating another user)
 * - Check and enforce ban status
 *
 * @param session - The Better Auth session to enhance
 * @param event - H3 event for reading cookies
 * @returns Enhanced session or throws error if banned
 */
export async function enhanceSession(
  session: AuthSession | null,
  event: H3Event
): Promise<AuthSession> {
  if (!session || !session.user) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Unauthorized'
    })
  }

  const db = useDB()

  // Impersonation: if admin set cookie, override session user
  const impersonateUserId = getCookie(event, 'impersonateUserId')
  if (impersonateUserId && session.user.superAdmin) {
    const [imp] = await db
      .select({
        id: userTable.id,
        name: userTable.name,
        email: userTable.email,
        image: userTable.image,
        emailVerified: userTable.emailVerified,
        superAdmin: userTable.superAdmin,
        banned: userTable.banned,
        bannedUntil: userTable.bannedUntil
      })
      .from(userTable)
      .where(eq(userTable.id, impersonateUserId))
      .limit(1)
    if (imp) {
      // @ts-expect-error augmenting runtime object
      session.user = { ...session.user, ...imp, _impersonated: true }
    }
  }

  // Enforce ban server-side
  const [row] = await db
    .select({ banned: userTable.banned, bannedUntil: userTable.bannedUntil })
    .from(userTable)
    .where(eq(userTable.id, session.user.id))
    .limit(1)

  const now = new Date()
  const isBannedActive = Boolean(row?.banned) && (!row?.bannedUntil || (row.bannedUntil && row.bannedUntil > now))
  if (isBannedActive) {
    throw createError({ statusCode: 403, statusMessage: 'Account is banned' })
  }

  return session as unknown as AuthSession
}

/**
 * Require an authenticated user session with impersonation and ban checking.
 * Throws 401 if not authenticated, 403 if banned.
 */
export async function requireUserSession(event: H3Event): Promise<AuthSession> {
  const session = await resolveSession(event)

  if (!session || !session.user) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Unauthorized'
    })
  }

  return enhanceSession(session, event)
}

export async function requireSuperAdmin(event: H3Event): Promise<AuthSession> {
  const session = await requireUserSession(event)
  const db = useDB()
  const [row] = await db
    .select({ superAdmin: userTable.superAdmin })
    .from(userTable)
    .where(eq(userTable.id, session.user.id))
    .limit(1)

  if (!row?.superAdmin) {
    throw createError({ statusCode: 403, statusMessage: 'Forbidden' })
  }
  return session
}
