import { Request, Response, NextFunction } from 'express'
import { AppError } from './index'

function withRequestId(req: Request, payload: Record<string, unknown>) {
  return { ...payload, requestId: req.requestId }
}

export function errorMiddleware(err: any, req: Request, res: Response, _next: NextFunction) {
  if (err.name === 'ZodError') {
    return res.status(400).json(withRequestId(req, {
      error: 'validation_error',
      message: 'Invalid request body',
      issues: err.issues,
      statusCode: 400,
    }))
  }

  if (err.code === 'P2025') {
    return res.status(404).json(withRequestId(req, { error: 'not_found', message: 'Resource not found', statusCode: 404 }))
  }

  if (err.code === 'P2002') {
    return res.status(409).json(withRequestId(req, { error: 'conflict', message: 'A resource with this value already exists', statusCode: 409 }))
  }

  if (err.code === 'P2021' || err.code === 'P2022') {
    console.error('[API Error] Database schema mismatch', { requestId: req.requestId, err })
    return res.status(503).json(withRequestId(req, {
      error: 'database_schema_mismatch',
      message: 'Database schema is out of date. Run database migrations and retry.',
      statusCode: 503,
    }))
  }

  if (err instanceof AppError) {
    if (err.statusCode >= 500) console.error('[API Error]', { requestId: req.requestId, err })
    return res.status(err.statusCode).json(withRequestId(req, {
      error: err.error,
      message: err.statusCode >= 500 ? 'Internal server error' : err.message,
      statusCode: err.statusCode,
      ...(err.statusCode >= 500 ? {} : err.data),
    }))
  }

  const statusCode = typeof err.statusCode === 'number' ? err.statusCode : 500
  const safeStatusCode = statusCode >= 400 && statusCode < 600 ? statusCode : 500

  if (safeStatusCode >= 500) {
    console.error('[API Error]', { requestId: req.requestId, err })
  }

  res.status(safeStatusCode).json(withRequestId(req, {
    error: safeStatusCode >= 500 ? 'internal_error' : (err.code ?? 'request_error'),
    message: safeStatusCode >= 500 ? 'Internal server error' : (err.message ?? 'Request failed'),
    statusCode: safeStatusCode,
  }))
}
