/**
 * Structured logger with log levels.
 * Level controlled by LOG_LEVEL env var (debug|info|warn|error).
 * Default: 'info' in production, 'debug' otherwise.
 */

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

interface LogEntry {
  level: LogLevel;
  message: string;
  timestamp: string;
  module?: string;
  duration?: number;
  error?: string;
}

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

let currentLevel: LogLevel =
  (process.env.LOG_LEVEL as LogLevel) ||
  (process.env.NODE_ENV === 'production' ? 'info' : 'debug');

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

function formatLog(entry: LogEntry): string {
  const parts: string[] = [
    `[${entry.timestamp}]`,
    `[${entry.level.toUpperCase()}]`,
  ];
  if (entry.module) parts.push(`[${entry.module}]`);
  parts.push(entry.message);
  if (entry.duration !== undefined) parts.push(`(${entry.duration}ms)`);
  if (entry.error) parts.push(`\n  ${entry.error}`);
  return parts.join(' ');
}

function log(level: LogLevel, message: string, module?: string, extra?: Partial<LogEntry>): void {
  if (!shouldLog(level)) return;
  const entry: LogEntry = {
    level,
    message,
    timestamp: new Date().toISOString(),
    module,
    ...extra,
  };
  const formatted = formatLog(entry);
  switch (level) {
    case 'error':
      console.error(formatted);
      break;
    case 'warn':
      console.warn(formatted);
      break;
    default:
      console.log(formatted);
      break;
  }
}

export const logger = {
  debug: (msg: string, module?: string) => log('debug', msg, module),
  info: (msg: string, module?: string) => log('info', msg, module),
  warn: (msg: string, module?: string) => log('warn', msg, module),
  error: (msg: string, module?: string, err?: Error) =>
    log('error', msg, module, err ? { error: err.stack || err.message } : undefined),
  /** Log with duration (for performance tracking) */
  perf: (msg: string, durationMs: number, module?: string) =>
    log('info', msg, module, { duration: durationMs }),
};
