/**
 * MFA (Multi-Factor Authentication) Middleware
 * Requires TOTP verification for admin users
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { getPrismaClient } from '../db/prisma.js';
import { createLogger } from '@4runr/shared';
import { authenticator } from 'otplib';
import { openMfaSecret } from '../crypto/mfa-storage.js';

const logger = createLogger('Gateway:Auth:MFA');

/**
 * Check if user has admin role
 */
async function isAdmin(userId: string): Promise<boolean> {
  try {
    const prisma = await getPrismaClient();
    const user = await prisma.user.findUnique({
      where: { id: userId },
      include: {
        roles: {
          include: {
            role: true
          }
        }
      }
    });

    if (!user) return false;

    // Check if user has admin role
    return user.roles.some(ur => ur.role.name === 'admin');
  } catch (error) {
    logger.error('Error checking admin role', { error, userId });
    return false;
  }
}

/**
 * Verify TOTP token
 */
async function verifyMFA(userId: string, token: string): Promise<boolean> {
  try {
    const prisma = await getPrismaClient();
    const user = await prisma.user.findUnique({
      where: { id: userId }
    });

    if (!user || !user.mfaEnabled || !user.mfaSecret) {
      return false;
    }

    const secret = openMfaSecret(user.mfaSecret);
    if (!secret) {
      return false;
    }

    const isValid = authenticator.verify({ token, secret });

    if (isValid) {
      // Update last verified time
      await prisma.user.update({
        where: { id: userId },
        data: { mfaVerifiedAt: new Date() }
      });
    }

    return isValid;
  } catch (error) {
    logger.error('Error verifying MFA', { error, userId });
    return false;
  }
}

/**
 * Require MFA for admin users
 */
export async function requireMFA(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  // Get user from request (set by auth middleware)
  const auth = (request as any).auth || (request as any).user;
  if (!auth || !auth.sub) {
    reply.status(401).send({
      error: 'unauthorized',
      message: 'Authentication required'
    });
    return;
  }

  const userId = auth.sub;

  // Check if user is admin
  const isAdminUser = await isAdmin(userId);
  if (!isAdminUser) {
    // Non-admin users don't need MFA
    return;
  }

  // Check if MFA is enabled for this admin
  const prisma = await getPrismaClient();
  const user = await prisma.user.findUnique({
    where: { id: userId }
  });

  if (!user || !user.mfaEnabled) {
    // MFA not enabled - allow but warn
    logger.warn('Admin user without MFA', { userId });
    return;
  }

  // Check for MFA token in header
  const mfaToken = request.headers['x-mfa-token'] as string | undefined;
  if (!mfaToken) {
    reply.status(403).send({
      error: 'mfa_required',
      message: 'MFA token required for admin access',
      mfaRequired: true
    });
    return;
  }

  // Verify MFA token
  const isValid = await verifyMFA(userId, mfaToken);
  if (!isValid) {
    reply.status(403).send({
      error: 'mfa_invalid',
      message: 'Invalid MFA token'
    });
    return;
  }

  // MFA verified - attach to request
  (request as any).mfaVerified = true;
}

