/**
 * Structured Logger
 *
 * Provides consistent, structured logging across the application.
 * - In development: pretty-prints to console with colors
 * - In production: outputs JSON for log aggregation (Logtail, Datadog, etc.)
 *
 * Usage:
 *   import { logger } from '@/utils/logger';
 *   logger.info('api.contact', 'Form submitted', { email: '...' });
 *   logger.error('api.contact', 'Email failed', { error: err.message });
 */

type LogLevel = 'debug' | 'info' | 'warn' | 'error';

interface LogEntry {
  level: LogLevel;
  scope: string;
  message: string;
  timestamp: string;
  [key: string]: unknown;
}

const LEVELS: Record<LogLevel, number> = {
  debug: 0,
  info: 1,
  warn: 2,
  error: 3,
};

// Minimum log level — override via LOG_LEVEL env var
function getMinLevel(): LogLevel {
  const env = (typeof process !== 'undefined' && process.env.LOG_LEVEL) ||
              (typeof import.meta !== 'undefined' && (import.meta as { env?: { LOG_LEVEL?: string } }).env?.LOG_LEVEL);
  if (env && env in LEVELS) return env as LogLevel;
  return (typeof import.meta !== 'undefined' && (import.meta as { env?: { PROD?: boolean } }).env?.PROD)
    ? 'info'
    : 'debug';
}

function shouldLog(level: LogLevel): boolean {
  return LEVELS[level] >= LEVELS[getMinLevel()];
}

function formatEntry(level: LogLevel, scope: string, message: string, meta?: Record<string, unknown>): LogEntry {
  return {
    level,
    scope,
    message,
    timestamp: new Date().toISOString(),
    ...meta,
  };
}

const isProd = typeof import.meta !== 'undefined'
  ? (import.meta as { env?: { PROD?: boolean } }).env?.PROD === true
  : process.env.NODE_ENV === 'production';

const COLORS: Record<LogLevel, string> = {
  debug: '\x1b[90m', // gray
  info:  '\x1b[36m', // cyan
  warn:  '\x1b[33m', // yellow
  error: '\x1b[31m', // red
};
const RESET = '\x1b[0m';

function output(entry: LogEntry): void {
  if (isProd) {
    // JSON output for log aggregation in production
    // eslint-disable-next-line no-console
    console.log(JSON.stringify(entry));
  } else {
    const color = COLORS[entry.level] ?? '';
    const { level, scope, message, timestamp, ...rest } = entry;
    const meta = Object.keys(rest).length > 0 ? ' ' + JSON.stringify(rest) : '';
    // eslint-disable-next-line no-console
    console.log(`${color}[${level.toUpperCase()}]${RESET} ${timestamp} [${scope}] ${message}${meta}`);
  }
}

function log(level: LogLevel, scope: string, message: string, meta?: Record<string, unknown>): void {
  if (!shouldLog(level)) return;
  output(formatEntry(level, scope, message, meta));
}

export const logger = {
  debug: (scope: string, message: string, meta?: Record<string, unknown>) => log('debug', scope, message, meta),
  info:  (scope: string, message: string, meta?: Record<string, unknown>) => log('info',  scope, message, meta),
  warn:  (scope: string, message: string, meta?: Record<string, unknown>) => log('warn',  scope, message, meta),
  error: (scope: string, message: string, meta?: Record<string, unknown>) => log('error', scope, message, meta),
};

/**
 * Log an API request/response pair. Use at the end of API handlers.
 */
export function logApiRequest(opts: {
  scope: string;
  method: string;
  path: string;
  status: number;
  ip?: string;
  durationMs?: number;
  meta?: Record<string, unknown>;
}): void {
  const { scope, method, path, status, ip, durationMs, meta } = opts;
  const level: LogLevel = status >= 500 ? 'error' : status >= 400 ? 'warn' : 'info';
  log(level, scope, `${method} ${path} ${status}`, {
    method,
    path,
    status,
    ...(ip && { ip }),
    ...(durationMs !== undefined && { durationMs }),
    ...meta,
  });
}
