/**
 * API Key authentication middleware for Fastify
 * Validates x-api-key header against database
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { isPostgresMode } from '../config/persistence.js';
import { getPrismaClient } from '../db/prisma.js';
import { env, createLogger } from '@4runr/shared';

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

// Simple in-memory key store for memory mode
const memoryApiKeys = new Map<string, { label?: string; revoked: boolean }>();

/**
 * Initialize memory API keys from environment
 * In memory mode, we can use API_KEY env var (comma-separated list of keys)
 */
function initializeMemoryApiKeys() {
  const apiKeys = process.env['API_KEY'] || process.env['API_KEYS'];
  if (apiKeys) {
    const keys = apiKeys.split(',').map(k => k.trim()).filter(Boolean);
    keys.forEach((key, index) => {
      memoryApiKeys.set(key, {
        label: `Memory Key ${index + 1}`,
        revoked: false,
      });
    });
  }
  
  // Also support a single key for convenience
  const singleKey = process.env['API_KEY'];
  if (singleKey && !apiKeys?.includes(',')) {
    memoryApiKeys.set(singleKey, {
      label: 'Default API Key',
      revoked: false,
    });
  }
}

// Initialize on module load
initializeMemoryApiKeys();

/**
 * Validate API key
 */
async function validateApiKey(key: string): Promise<{ valid: boolean; revoked: boolean }> {
  if (isPostgresMode()) {
    try {
      const prisma = await getPrismaClient();
      const apiKey = await prisma.apiKey.findUnique({
        where: { key },
      });

      if (!apiKey) {
        return { valid: false, revoked: false };
      }

      return {
        valid: true,
        revoked: apiKey.revoked,
      };
    } catch (error) {
      logger.error('Error validating API key', { error: error instanceof Error ? error.message : String(error) });
      return { valid: false, revoked: false };
    }
  } else {
    // Memory mode - use in-memory map
    const apiKey = memoryApiKeys.get(key);
    if (!apiKey) {
      return { valid: false, revoked: false };
    }

    return {
      valid: true,
      revoked: apiKey.revoked,
    };
  }
}

/**
 * Fastify middleware to require API key authentication
 */
export async function requireApiKey(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  // Skip auth if disabled
  if (!env.AUTH_ENABLED) {
    return;
  }

  // Skip for health/readiness endpoints
  const url = request.url || '/';
  const path = url.split('?')[0] || '/';
  if (
    path === '/health' ||
    path === '/ready' ||
    path === '/liveness' ||
    path === '/startup' ||
    path === '/metrics' ||
    (path && path.startsWith('/debug/'))
  ) {
    return;
  }

  const apiKey = request.headers['x-api-key'] as string | undefined;

  if (!apiKey) {
    reply.status(401).send({
      error: 'Unauthorized',
      message: 'Missing x-api-key header',
    });
    return;
  }

  const validation = await validateApiKey(apiKey);

  if (!validation.valid) {
    reply.status(401).send({
      error: 'Unauthorized',
      message: 'Invalid API key',
    });
    return;
  }

  if (validation.revoked) {
    reply.status(403).send({
      error: 'Forbidden',
      message: 'API key has been revoked',
    });
    return;
  }

  // Attach API key info to request for downstream use
  (request as any).apiKey = apiKey;
}

/**
 * Optional API key authentication (doesn't fail if missing)
 */
export async function optionalApiKey(
  request: FastifyRequest,
  reply: FastifyReply
): Promise<void> {
  const apiKey = request.headers['x-api-key'] as string | undefined;

  if (apiKey) {
    const validation = await validateApiKey(apiKey);
    if (validation.valid && !validation.revoked) {
      (request as any).apiKey = apiKey;
    }
  }
}

