/**
 * JWT authentication middleware for Fastify
 * Validates Authorization: Bearer <token> header
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { env, createLogger } from '@4runr/shared';
import * as crypto from 'crypto';

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

/**
 * JWT payload structure
 */
export interface AuthContext {
  sub?: string;           // Subject (user ID)
  tenantId?: string;      // Tenant/organization ID
  roles?: string[];       // User roles
  exp?: number;           // Expiration time (Unix timestamp)
  iat?: number;           // Issued at (Unix timestamp)
  [key: string]: any;     // Additional custom claims
}

/**
 * Decode and verify JWT token
 */
function verifyJwt(token: string, secret: string, algorithm: string = 'HS256'): AuthContext | null {
  try {
    const parts = token.split('.');
    if (parts.length !== 3) {
      return null;
    }

    const [headerB64, payloadB64, signatureB64] = parts;
    
    // Verify signature
    const signatureCheck = crypto
      .createHmac(algorithm.toLowerCase().replace('hs', 'sha'), secret)
      .update(`${headerB64}.${payloadB64}`)
      .digest('base64url');

    if (signatureCheck !== signatureB64) {
      return null;
    }

    // Decode payload
    if (!payloadB64) {
      return null;
    }
    const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));

    // Check expiration
    if (payload.exp && Date.now() >= payload.exp * 1000) {
      return null;
    }

    return payload;
  } catch (error) {
    logger.error('JWT verification error', { error: error instanceof Error ? error.message : String(error) });
    return null;
  }
}

/**
 * Fastify middleware to require JWT authentication
 */
export async function requireJwt(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  const authorization = request.headers.authorization;

  if (!authorization || !authorization.startsWith('Bearer ')) {
    reply.status(401).send({
      error: 'unauthorized',
      reason: 'invalid_or_missing_credentials',
      message: 'Missing or invalid Authorization header. Expected: Authorization: Bearer <token>',
    });
    return;
  }

  const token = authorization.substring(7); // Remove "Bearer " prefix

  if (!env.JWT_SECRET) {
    reply.status(500).send({
      error: 'server_error',
      message: 'JWT authentication is not configured',
    });
    return;
  }

  const decoded = verifyJwt(token, env.JWT_SECRET, env.JWT_ALG);

  if (!decoded) {
    reply.status(401).send({
      error: 'unauthorized',
      reason: 'invalid_or_missing_credentials',
      message: 'Invalid or expired JWT token',
    });
    return;
  }

  // Attach decoded JWT payload to request for downstream use
  (request as any).auth = decoded;
  (request as any).user = decoded; // Alias for convenience
}

/**
 * Optional JWT authentication (doesn't fail if missing)
 */
export async function optionalJwt(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  const authorization = request.headers.authorization;

  if (authorization && authorization.startsWith('Bearer ')) {
    const token = authorization.substring(7);
    
    if (env.JWT_SECRET) {
      const decoded = verifyJwt(token, env.JWT_SECRET, env.JWT_ALG);
      if (decoded) {
        (request as any).auth = decoded;
        (request as any).user = decoded;
      }
    }
  }
}

