import morgan from 'morgan';
import type { Request } from 'express';
import logger from '../config/logger.js';

interface AccessLogEntry {
  requestId: string;
  ip: string;
  method: string;
  url: string;
  status: number;
  responseTimeMs: number;
  contentLength: string;
  userAgent: string;
}

// One JSON line per request: who (ip, user-agent), what (method, url),
// and outcome (status, response time). 4xx/5xx are logged louder (warn/error)
// so failed logins, validation errors, and scans stand out from normal traffic.
// requestId (set by requestId.ts, which runs before this) lets one request be
// traced across log lines and correlated with the X-Request-Id response header.
const format: morgan.FormatFn<Request> = (tokens, req, res) => JSON.stringify({
  requestId: req.id ?? '-',
  ip: tokens['remote-addr'](req, res) ?? '-',
  method: tokens.method(req, res) ?? '-',
  url: tokens.url(req, res) ?? '-',
  status: Number(tokens.status(req, res)),
  responseTimeMs: Number(tokens['response-time'](req, res, 3)),
  contentLength: tokens.res(req, res, 'content-length') ?? '0',
  userAgent: tokens['user-agent'](req, res) ?? '-',
} satisfies AccessLogEntry);

const stream: morgan.StreamOptions = {
  write(line: string) {
    const entry = JSON.parse(line) as AccessLogEntry;
    const level = entry.status >= 500 ? 'error' : entry.status >= 400 ? 'warn' : 'http';
    logger.log(level, `${entry.method} ${entry.url} ${entry.status}`, entry);
  },
};

export default morgan(format, { stream });
