/**
 * Monitoring Logger
 *
 * Structured logger that writes entries to the monitoring-logs collection.
 * Falls back to console output when Payload is not yet initialized.
 */

import type { LogLevel, LogSource } from "./types";

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

function getMinLevel(): LogLevel {
  return (process.env.MONITORING_LOG_LEVEL as LogLevel) || "info";
}

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

export interface LogContext {
  requestId?: string;
  userId?: number;
  tenant?: number;
  duration?: number;
  [key: string]: unknown;
}

export interface MonitoringLoggerInstance {
  debug(message: string, context?: LogContext): void;
  info(message: string, context?: LogContext): void;
  warn(message: string, context?: LogContext): void;
  error(message: string, context?: LogContext): void;
  fatal(message: string, context?: LogContext): void;
}

/** Cached Payload instance — resolved once, reused for all subsequent writes. */
let cachedPayload: any = null;

async function getPayloadInstance(): Promise<any> {
  if (cachedPayload) return cachedPayload;
  const { getPayload } = await import("payload");
  const config = (await import(/* @vite-ignore */ "@payload-config")).default;
  cachedPayload = await getPayload({ config });
  return cachedPayload;
}

/** Reset cached instance (used in tests). */
export function _resetPayloadCache(): void {
  cachedPayload = null;
}

async function writeLog(source: LogSource, level: LogLevel, message: string, context?: LogContext): Promise<void> {
  if (!shouldLog(level)) return;

  try {
    const payload = await getPayloadInstance();

    const { requestId, userId, tenant, duration, ...rest } = context || {};

    await payload.create({
      collection: "monitoring-logs",
      data: {
        level,
        source,
        message,
        context: Object.keys(rest).length > 0 ? rest : undefined,
        requestId,
        userId,
        tenant,
        duration,
      },
    });
  } catch {
    // Fallback to console if Payload is not yet initialized
    cachedPayload = null;
    const prefix = `[${source}][${level.toUpperCase()}]`;
    console.log(prefix, message, context || "");
  }
}

export function createMonitoringLogger(source: LogSource): MonitoringLoggerInstance {
  function log(level: LogLevel): (message: string, context?: LogContext) => void {
    return function logMessage(message: string, context?: LogContext): void {
      // Fire-and-forget -- don't block the caller
      writeLog(source, level, message, context).catch(function onError(err) {
        console.error(`[MonitoringLogger] Failed to write ${level} log:`, err);
      });
    };
  }

  return {
    debug: log("debug"),
    info: log("info"),
    warn: log("warn"),
    error: log("error"),
    fatal: log("fatal"),
  };
}
