/**
 * Security Configuration
 *
 * Implements OWASP Top 10 security best practices
 */

import { HelmetOptions } from 'helmet';

export const helmetConfig: HelmetOptions = {
  // Content Security Policy
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"], // Required for inline styles in some frameworks
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", 'data:', 'https:'],
      connectSrc: ["'self'"],
      fontSrc: ["'self'"],
      objectSrc: ["'none'"],
      mediaSrc: ["'self'"],
      frameSrc: ["'none'"],
    },
  },

  // Cross-Origin Embedder Policy
  crossOriginEmbedderPolicy: false, // Set to true in production if needed

  // Cross-Origin Opener Policy
  crossOriginOpenerPolicy: { policy: 'same-origin' },

  // Cross-Origin Resource Policy
  crossOriginResourcePolicy: { policy: 'same-origin' },

  // DNS Prefetch Control
  dnsPrefetchControl: { allow: false },

  // Frameguard
  frameguard: { action: 'deny' },

  // Hide Powered-By
  hidePoweredBy: true,

  // HSTS (HTTP Strict Transport Security)
  hsts: {
    maxAge: 31536000, // 1 year
    includeSubDomains: true,
    preload: true,
  },

  // IE No Open
  ieNoOpen: true,

  // No Sniff
  noSniff: true,

  // Origin Agent Cluster
  originAgentCluster: true,

  // Permitted Cross-Domain Policies
  permittedCrossDomainPolicies: { permittedPolicies: 'none' },

  // Referrer Policy
  referrerPolicy: { policy: 'no-referrer' },

  // XSS Filter
  xssFilter: true,
};

/**
 * Rate Limiting Configuration
 */
export const rateLimitConfig = {
  // Global rate limit
  global: {
    ttl: 60, // 60 seconds
    limit: 100, // 100 requests per minute
  },

  // Auth endpoints (more strict)
  auth: {
    ttl: 60,
    limit: 5, // 5 login attempts per minute
  },

  // Search endpoints
  search: {
    ttl: 60,
    limit: 30, // 30 searches per minute
  },

  // Booking endpoints
  booking: {
    ttl: 60,
    limit: 20, // 20 bookings per minute
  },
};

/**
 * Allowed CORS origins.
 *
 * Reads CORS_ORIGIN (comma-separated list — supports several frontend hosts such
 * as app.* and www.*), falling back to FRONTEND_URL, then to localhost in dev.
 * With `credentials: true` the browser requires an exact origin echo (no `*`),
 * so we resolve the request origin against this allow-list per request.
 */
const allowedOrigins: string[] = (
  process.env.CORS_ORIGIN ||
  process.env.FRONTEND_URL ||
  'http://localhost:3000,http://localhost:3001'
)
  .split(',')
  .map(origin => origin.trim())
  .filter(Boolean);

/**
 * CORS Configuration
 */
export const corsConfig = {
  origin: (
    requestOrigin: string | undefined,
    callback: (err: Error | null, allow?: boolean) => void
  ): void => {
    // Allow non-browser clients (no Origin header: server-to-server, curl, health checks).
    if (!requestOrigin || allowedOrigins.includes(requestOrigin)) {
      callback(null, true);
      return;
    }
    callback(null, false);
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
  exposedHeaders: ['X-Total-Count', 'X-Page-Count'],
  maxAge: 86400, // 24 hours
};

/**
 * Password Policy
 */
export const passwordPolicy = {
  minLength: 12,
  requireUppercase: true,
  requireLowercase: true,
  requireNumbers: true,
  requireSymbols: true,
  maxLength: 128,
  preventCommon: true, // Prevent common passwords
  preventReuse: 5, // Last 5 passwords
};

/**
 * File Upload Configuration
 */
export const fileUploadConfig = {
  maxFileSize: 10 * 1024 * 1024, // 10MB
  allowedMimeTypes: [
    'application/pdf',
    'image/jpeg',
    'image/png',
    'image/webp',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'text/csv',
  ],
  allowedExtensions: ['.pdf', '.jpg', '.jpeg', '.png', '.webp', '.xls', '.xlsx', '.csv'],
  scanForViruses: process.env.NODE_ENV === 'production',
};

/**
 * Auth Cookie Configuration
 *
 * Tokens are delivered as httpOnly cookies so they are not readable from
 * JavaScript (XSS mitigation). COOKIE_DOMAIN must be set in production when
 * the API and the frontend live on different subdomains (e.g. ".xpeditis.com").
 */
export const AUTH_COOKIE_NAMES = {
  accessToken: 'accessToken',
  refreshToken: 'refreshToken',
  /** Non-httpOnly flag the frontend reads to know a session exists (contains no token) */
  session: 'xpeditis_session',
} as const;

export function authCookieOptions(options?: { maxAgeMs?: number; httpOnly?: boolean }): {
  httpOnly: boolean;
  secure: boolean;
  sameSite: 'lax' | 'strict' | 'none';
  path: string;
  domain?: string;
  maxAge?: number;
} {
  // SameSite must be 'none' when the frontend and the API live on different
  // sites (cross-origin), otherwise the browser drops the auth cookies set in
  // the cross-site login XHR response. 'none' REQUIRES Secure (HTTPS).
  // Configurable via COOKIE_SAMESITE; defaults to 'lax' for same-site setups.
  const sameSite =
    (process.env.COOKIE_SAMESITE?.toLowerCase() as 'lax' | 'strict' | 'none') || 'lax';
  const secure = process.env.NODE_ENV === 'production' || sameSite === 'none';

  return {
    httpOnly: options?.httpOnly ?? true,
    secure,
    sameSite,
    path: '/',
    ...(process.env.COOKIE_DOMAIN ? { domain: process.env.COOKIE_DOMAIN } : {}),
    ...(options?.maxAgeMs ? { maxAge: options.maxAgeMs } : {}),
  };
}

/**
 * Brute Force Protection
 */
export const bruteForceConfig = {
  freeRetries: 3,
  minWait: 5 * 60 * 1000, // 5 minutes
  maxWait: 60 * 60 * 1000, // 1 hour
  lifetime: 24 * 60 * 60, // 24 hours
};
