import type { LogLevel, LogPayload, Logger, LoggerConfig } from './types.js';

function formatPayload(
  service: string,
  level: LogLevel,
  message: string,
  error?: unknown,
  extra?: Record<string, unknown>
): LogPayload {
  const payload: LogPayload = {
    level,
    message,
    timestamp: new Date().toISOString(),
    service,
    ...extra,
  };

  if (error instanceof Error) {
    payload.error = error.message;
    payload.stack = error.stack;
  } else if (error !== undefined) {
    payload.error = String(error);
  }

  return payload;
}

function emit(payload: LogPayload, isDev: boolean): void {
  if (isDev) {
    const { level, message, error: err, ...rest } = payload;
    const prefix = `[${level.toUpperCase()}]`;
    const extras = Object.keys(rest).length > 2 ? ` ${JSON.stringify(rest)}` : '';
    const errStr = err ? ` — ${err}` : '';

    if (level === 'error' || level === 'warn') {
      // eslint-disable-next-line no-console
      console.error(`${prefix} ${message}${errStr}${extras}`);
    } else {
      // eslint-disable-next-line no-console
      console.log(`${prefix} ${message}${extras}`);
    }
  } else {
    const out = JSON.stringify(payload);
    if (payload.level === 'error' || payload.level === 'warn') {
      process.stderr.write(out + '\n');
    } else {
      process.stdout.write(out + '\n');
    }
  }
}

/**
 * Create a structured logger for a service or dashboard.
 *
 * @example
 * ```ts
 * import { createLogger } from "@bytelyst/logger";
 * const log = createLogger({ service: "admin-dashboard" });
 * log.error("Login failed", error, { userId });
 * log.info("Seed complete", { containers: 8 });
 * ```
 */
export function createLogger(config: LoggerConfig): Logger {
  const { service } = config;
  const isDev = config.isDev ?? process.env.NODE_ENV !== 'production';

  return {
    error(message: string, error?: unknown, extra?: Record<string, unknown>): void {
      emit(formatPayload(service, 'error', message, error, extra), isDev);
    },
    warn(message: string, extra?: Record<string, unknown>): void {
      emit(formatPayload(service, 'warn', message, undefined, extra), isDev);
    },
    info(message: string, extra?: Record<string, unknown>): void {
      emit(formatPayload(service, 'info', message, undefined, extra), isDev);
    },
    debug(message: string, extra?: Record<string, unknown>): void {
      if (isDev) {
        emit(formatPayload(service, 'debug', message, undefined, extra), isDev);
      }
    },
  };
}
