/**
 * Request Logger — Canonical Log Lines
 *
 * Generates a single comprehensive log entry per request that captures
 * the complete story: who, what, where, when, and how long.
 *
 * This is the "TL;DR" for every request — instead of scattered logs,
 * one canonical line tells you everything important.
 *
 * Designed for Edge runtime compatibility (no Node.js-only APIs).
 */

export interface CanonicalLogLine {
  /** ISO timestamp */
  timestamp: string;
  /** HTTP method */
  method: string;
  /** Request path (without query params) */
  path: string;
  /** HTTP status code */
  statusCode: number;
  /** Request duration in milliseconds */
  durationMs: number;
  /** Correlation ID for distributed tracing */
  correlationId: string;
  /** Unique request ID */
  requestId: string;
  /** Client IP (sanitized in production) */
  clientIp: string;
  /** User-Agent string (truncated) */
  userAgent: string;
  /** Content-Type of request */
  contentType: string;
  /** Whether rate limit was triggered */
  rateLimited: boolean;
  /** Request category for grouping */
  category: RequestCategory;
  /** Content-Length of response if available */
  responseSize?: number;
}

export type RequestCategory =
  | 'api:auth'
  | 'api:staff'
  | 'api:billing'
  | 'api:stripe'
  | 'api:dashboard'
  | 'api:health'
  | 'api:public'
  | 'page:dashboard'
  | 'page:staff'
  | 'page:public'
  | 'static'
  | 'other';

/**
 * Categorize a request path for grouping in metrics and logs.
 */
export function categorizeRequest(pathname: string): RequestCategory {
  if (pathname.startsWith('/api/auth/')) return 'api:auth';
  if (pathname.startsWith('/api/staff/')) return 'api:staff';
  if (pathname.startsWith('/api/billing/') || pathname.startsWith('/api/stripe/')) return 'api:billing';
  if (pathname.startsWith('/api/subscription/') || pathname.startsWith('/api/subscriptions/')) return 'api:billing';
  if (pathname.startsWith('/api/dashboard/')) return 'api:dashboard';
  if (pathname.startsWith('/api/health/')) return 'api:health';
  if (pathname.startsWith('/api/')) return 'api:public';
  if (pathname.includes('/dashboard')) return 'page:dashboard';
  if (pathname.startsWith('/staff/')) return 'page:staff';
  if (pathname.startsWith('/_next/')) return 'static';
  return 'page:public';
}

/**
 * Sanitize IP address for production logs.
 * Keeps first two octets for geographic grouping, masks the rest.
 */
function sanitizeIp(ip: string, isProduction: boolean): string {
  if (!isProduction) return ip;

  // IPv4: keep first two octets
  const ipv4Match = ip.match(/^(\d{1,3}\.\d{1,3})\.\d{1,3}\.\d{1,3}$/);
  if (ipv4Match) return `${ipv4Match[1]}.x.x`;

  // IPv6 or other: mask completely
  return '[masked]';
}

/**
 * Truncate User-Agent to a reasonable length.
 */
function truncateUserAgent(ua: string, maxLength = 120): string {
  if (!ua) return 'unknown';
  return ua.length > maxLength ? ua.substring(0, maxLength) + '...' : ua;
}

/**
 * Build a canonical log line from request/response data.
 * Call this once per request — at the end, after the response is ready.
 */
export function buildCanonicalLogLine(params: {
  method: string;
  pathname: string;
  statusCode: number;
  startTime: number;
  correlationId: string;
  requestId: string;
  clientIp: string;
  userAgent: string;
  contentType: string;
  rateLimited: boolean;
  responseSize?: number;
}): CanonicalLogLine {
  const isProduction = process.env.NODE_ENV === 'production';

  return {
    timestamp: new Date().toISOString(),
    method: params.method,
    path: params.pathname,
    statusCode: params.statusCode,
    durationMs: Date.now() - params.startTime,
    correlationId: params.correlationId,
    requestId: params.requestId,
    clientIp: sanitizeIp(params.clientIp, isProduction),
    userAgent: truncateUserAgent(params.userAgent),
    contentType: params.contentType || 'none',
    rateLimited: params.rateLimited,
    category: categorizeRequest(params.pathname),
    responseSize: params.responseSize,
  };
}

/**
 * Format a canonical log line as a structured JSON string.
 * This is what gets written to stdout/shipped to Loki.
 */
export function formatCanonicalLog(line: CanonicalLogLine): string {
  const level = line.statusCode >= 500 ? 'error'
    : line.statusCode >= 400 ? 'warn'
    : 'info';

  return JSON.stringify({
    ...line,
    level,
    type: 'canonical',
    message: `${line.method} ${line.path} ${line.statusCode} ${line.durationMs}ms`,
    service: process.env.LOG_SERVICE_NAME || 'mawidi-site',
    environment: process.env.NODE_ENV,
  });
}
