import jwt from 'jsonwebtoken'
import Member from '../models/member.js'
import { connectDB } from './mongoose.js'

/**
 * Issue a session JWT and set the auth-token cookie for the given member.
 * Mirrors the cookie options used by verify.post.js.
 */
export function setAuthCookie(event, member) {
  const token = jwt.sign(
    { memberId: member._id.toString(), email: member.email, tv: member.tokenVersion || 0 },
    useRuntimeConfig(event).jwtSecret,
    { expiresIn: '7d' }
  )

  setCookie(event, 'auth-token', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/',
    maxAge: 60 * 60 * 24 * 7
  })
}

/**
 * Verify JWT from cookie and return the decoded member.
 * Throws 401 if token is missing or invalid.
 */
export async function requireAuth(event) {
  await connectDB()

  const token = getCookie(event, 'auth-token')

  if (!token) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Authentication required'
    })
  }

  let decoded
  try {
    decoded = jwt.verify(token, useRuntimeConfig().jwtSecret)
  } catch (err) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Invalid or expired token'
    })
  }

  const member = await Member.findById(decoded.memberId)

  if (!member) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Member not found'
    })
  }

  if (member.status === 'suspended' || member.status === 'cancelled') {
    throw createError({
      statusCode: 403,
      statusMessage: 'Account is ' + member.status
    })
  }

  // Verify session has not been revoked (tokenVersion incremented on logout)
  if (decoded.tv !== member.tokenVersion) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Session has been revoked'
    })
  }

  return member
}

/**
 * Return the signed-in Member without throwing.
 * Returns null when no cookie, invalid token, or member not found/inactive.
 * Mirrors the non-throwing JWT check in api/auth/status.get.js.
 */
export async function getOptionalMember(event) {
  await connectDB()

  const token = getCookie(event, 'auth-token')
  if (!token) return null

  let decoded
  try {
    decoded = jwt.verify(token, useRuntimeConfig(event).jwtSecret)
  } catch {
    return null
  }

  const member = await Member.findById(decoded.memberId)
  if (!member) return null
  if (member.status === 'suspended' || member.status === 'cancelled') return null
  if (decoded.tv !== member.tokenVersion) return null

  return member
}

/**
 * Verify JWT and require admin role.
 * Throws 401 if not authenticated, 403 if not admin.
 */
export async function requireAdmin(event) {
  const member = await requireAuth(event)

  if (member.role !== 'admin') {
    throw createError({
      statusCode: 403,
      statusMessage: 'Admin access required'
    })
  }

  return member
}
