import { eq } from 'drizzle-orm'
import { env } from '../config.js'
import { db } from '../db/client.js'
import { authSessions, users } from '../db/schema.js'
import { createSessionToken, hashSessionToken } from './password.js'

function getBearerToken(request) {
  const authorization = request.headers.authorization

  if (!authorization?.startsWith('Bearer ')) {
    return null
  }

  return authorization.slice('Bearer '.length).trim()
}

export function getSessionTokenFromRequest(request) {
  return getBearerToken(request)
}

export async function createSession(userId) {
  const token = createSessionToken()
  const tokenHash = hashSessionToken(token)
  const now = Date.now()
  const expiresAt = now + env.SESSION_TTL_DAYS * 24 * 60 * 60 * 1000

  const [session] = await db
    .insert(authSessions)
    .values({
      userId,
      tokenHash,
      expiresAt: new Date(expiresAt),
      createdAt: new Date(now),
    })
    .returning()

  return {
    token,
    session,
  }
}

export async function findAuthenticatedUser(request) {
  const token = getBearerToken(request)

  if (!token) {
    return null
  }

  const tokenHash = hashSessionToken(token)

  const [session] = await db
    .select()
    .from(authSessions)
    .where(eq(authSessions.tokenHash, tokenHash))
    .limit(1)

  if (!session || new Date(session.expiresAt).getTime() <= Date.now()) {
    return null
  }

  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.id, session.userId))
    .limit(1)

  if (user?.disabledAt) {
    await db.delete(authSessions).where(eq(authSessions.id, session.id))
    return null
  }

  if (user && user.role !== 'admin' && !user.emailVerifiedAt) {
    await db.delete(authSessions).where(eq(authSessions.id, session.id))
    return null
  }

  return user ?? null
}

export async function revokeSessionByToken(token) {
  if (!token) {
    return false
  }

  const tokenHash = hashSessionToken(token)
  const deletedSessions = await db
    .delete(authSessions)
    .where(eq(authSessions.tokenHash, tokenHash))
    .returning({ id: authSessions.id })

  return deletedSessions.length > 0
}
