import type { Request, Response, NextFunction } from 'express'
import { createRequestId, logDebug, logInfo } from '../utils/logger.js'

export function accessLogMiddleware(req: Request, res: Response, next: NextFunction): void {
  const startedAt = Date.now()
  const requestId = resolveRequestId(req)

  req.requestId = requestId
  res.setHeader('X-Request-Id', requestId)

  res.on('finish', () => {
    if (shouldSkipAccessLog(req.originalUrl, res.statusCode)) {
      return
    }

    const writeLog =
      resolveAccessLogLevel(req.method, res.statusCode) === 'debug' ? logDebug : logInfo
    writeLog('[http/access]', 'request completed', {
      requestId,
      method: req.method,
      originalUrl: req.originalUrl,
      statusCode: res.statusCode,
      durationMs: Date.now() - startedAt,
      ip: req.ip,
      forwardedFor: String(req.headers['x-forwarded-for'] || ''),
      userAgent: String(req.headers['user-agent'] || ''),
      referer: String(req.headers.referer || ''),
      contentLength: Number(res.getHeader('content-length') || 0),
      actorUserId: req.adminSession?.userId || '',
      actorUsername: req.adminSession?.username || '',
      actorRole: req.adminSession?.role || '',
    })
  })

  next()
}

export function resolveAccessLogLevel(method: unknown, statusCode: unknown): 'debug' | 'info' {
  const normalizedMethod = String(method || '')
    .trim()
    .toUpperCase()
  const normalizedStatus = Number(statusCode || 0)
  return ['GET', 'HEAD'].includes(normalizedMethod) &&
    normalizedStatus >= 200 &&
    normalizedStatus < 400
    ? 'debug'
    : 'info'
}

function resolveRequestId(req: Request): string {
  const fromHeader = String(req.headers['x-request-id'] || '').trim()
  return fromHeader || createRequestId('req')
}

function shouldSkipAccessLog(originalUrl: string, statusCode: number): boolean {
  const pathname = String(originalUrl || '').split('?')[0] || ''
  return ['/health', '/health/live', '/health/ready'].includes(pathname) && Number(statusCode) < 400
}
