/**
 * CORS Middleware
 * Agent 4: Production Deployment
 *
 * Configures Cross-Origin Resource Sharing for API routes.
 */

import type { NextApiRequest, NextApiResponse, NextApiHandler } from 'next';
import { env } from '../config';

interface CorsConfig {
  origins: string[];
  methods: string[];
  allowedHeaders: string[];
  exposedHeaders: string[];
  credentials: boolean;
  maxAge: number;
}

const DEFAULT_CONFIG: CorsConfig = {
  origins: env.corsOrigins,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: [
    'Content-Type',
    'Authorization',
    'X-Requested-With',
    'X-Request-Id',
    'X-API-Key',
  ],
  exposedHeaders: [
    'X-Request-Id',
    'X-RateLimit-Limit',
    'X-RateLimit-Remaining',
    'X-RateLimit-Reset',
  ],
  credentials: true,
  maxAge: 86400, // 24 hours
};

/**
 * Check if origin is allowed
 */
function isOriginAllowed(origin: string | undefined, allowedOrigins: string[]): boolean {
  if (!origin) return false;

  return allowedOrigins.some((allowed) => {
    // Exact match
    if (allowed === origin) return true;

    // Wildcard subdomain match (e.g., *.example.com)
    if (allowed.startsWith('*.')) {
      const domain = allowed.slice(2);
      return origin.endsWith(domain) || origin === `https://${domain}` || origin === `http://${domain}`;
    }

    // All origins allowed
    if (allowed === '*') return true;

    return false;
  });
}

/**
 * Apply CORS headers to response
 */
export function applyCorsHeaders(
  req: NextApiRequest,
  res: NextApiResponse,
  config: CorsConfig = DEFAULT_CONFIG
): void {
  const origin = req.headers.origin;

  // Set allowed origin
  if (isOriginAllowed(origin, config.origins)) {
    res.setHeader('Access-Control-Allow-Origin', origin!);
  } else if (config.origins.includes('*')) {
    res.setHeader('Access-Control-Allow-Origin', '*');
  }

  // Set other CORS headers
  if (config.credentials) {
    res.setHeader('Access-Control-Allow-Credentials', 'true');
  }

  res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
  res.setHeader('Access-Control-Allow-Headers', config.allowedHeaders.join(', '));
  res.setHeader('Access-Control-Expose-Headers', config.exposedHeaders.join(', '));
  res.setHeader('Access-Control-Max-Age', config.maxAge.toString());
}

/**
 * CORS middleware for API routes
 */
export function withCors(
  handler: NextApiHandler,
  config?: Partial<CorsConfig>
): NextApiHandler {
  const mergedConfig: CorsConfig = { ...DEFAULT_CONFIG, ...config };

  return async (req: NextApiRequest, res: NextApiResponse) => {
    applyCorsHeaders(req, res, mergedConfig);

    // Handle preflight requests
    if (req.method === 'OPTIONS') {
      return res.status(204).end();
    }

    return handler(req, res);
  };
}

/**
 * Strict CORS for internal APIs only
 */
export const strictCors = (handler: NextApiHandler) =>
  withCors(handler, {
    origins: ['http://localhost:3001'],
    credentials: true,
  });

/**
 * Open CORS for public APIs
 */
export const openCors = (handler: NextApiHandler) =>
  withCors(handler, {
    origins: ['*'],
    credentials: false,
  });

// Export types
export type { CorsConfig };
