import morgan, { StreamOptions } from 'morgan';
import { Request, Response } from 'express';
import { logger } from '../utils/logger';

// ─── Stream: pipe Morgan output into Winston ─────────────────────────────────

const stream: StreamOptions = {
  write: (message: string) => {
    logger.http(message.trim());
  },
};

// ─── Custom Morgan Token: request body ──────────────────────────────────────

morgan.token('req-body', (req: Request) => {
  const body = { ...req.body };
  // Mask sensitive fields
  if (body.password) body.password = '***';
  if (body.confirmPassword) body.confirmPassword = '***';
  if (body.token) body.token = '***';
  return Object.keys(body).length ? JSON.stringify(body) : '-';
});

// ─── Custom Morgan Token: response body ─────────────────────────────────────

morgan.token('res-body', (_req: Request, res: Response) => {
  const rawBody = (res as any).__body;
  if (!rawBody) return '-';
  try {
    const parsed = typeof rawBody === 'string' ? JSON.parse(rawBody) : rawBody;
    return JSON.stringify(parsed);
  } catch {
    return '-';
  }
});

// ─── Intercept res.json to capture response body ────────────────────────────

export const captureResponseBody = (
  req: Request,
  res: Response,
  next: () => void
): void => {
  const originalJson = res.json.bind(res);
  res.json = (body: any) => {
    (res as any).__body = body;
    return originalJson(body);
  };
  next();
};

// ─── Morgan Format ───────────────────────────────────────────────────────────

const morganFormat =
  ':remote-addr :method :url :status :res[content-length] - :response-time ms | body: :req-body | res: :res-body';

// ─── Skip health check route ─────────────────────────────────────────────────

const skip = (req: Request): boolean => req.url === '/';

// ─── Export Morgan Middleware ─────────────────────────────────────────────────

export const morganMiddleware = morgan(morganFormat, { stream, skip });
