import { Request, Response, NextFunction } from "express";
import { logger } from "../utils/logger";

// 커스텀 에러 클래스
export class AppError extends Error {
  public statusCode: number;
  public isOperational: boolean;

  constructor(message: string, statusCode: number = 500) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

// 에러 핸들러 미들웨어
export const errorHandler = (
  err: Error | AppError,
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  let error = { ...err };
  error.message = err.message;

  // PostgreSQL 에러 처리 (pg 라이브러리)
  if ((err as any).code) {
    const pgError = err as any;
    // 원본 에러 메시지 로깅 (디버깅용)
    console.error("🔴 PostgreSQL Error:", {
      code: pgError.code,
      message: pgError.message,
      detail: pgError.detail,
      hint: pgError.hint,
      table: pgError.table,
      column: pgError.column,
      constraint: pgError.constraint,
    });
    // PostgreSQL 에러 코드 참조: https://www.postgresql.org/docs/current/errcodes-appendix.html
    if (pgError.code === "23505") {
      // unique_violation
      const constraint = pgError.constraint || "";
      const tbl = pgError.table || "";
      let col = "";
      if (constraint && tbl) {
        const prefix = `${tbl}_`;
        const suffix = "_key";
        if (constraint.startsWith(prefix) && constraint.endsWith(suffix)) {
          col = constraint.slice(prefix.length, -suffix.length);
        }
      }
      const detail = col ? ` [${col}]` : "";
      error = new AppError(`중복된 데이터가 존재합니다.${detail}`, 400);
    } else if (pgError.code === "23503") {
      // foreign_key_violation
      error = new AppError("참조 무결성 제약 조건 위반입니다.", 400);
    } else if (pgError.code === "23502") {
      // not_null_violation
      const colName = pgError.column || "";
      const tableName = pgError.table || "";
      const detail = colName ? ` [${tableName}.${colName}]` : "";
      error = new AppError(`필수 입력값이 누락되었습니다.${detail}`, 400);
    } else if (pgError.code.startsWith("23")) {
      // 기타 무결성 제약 조건 위반
      error = new AppError("데이터 무결성 제약 조건 위반입니다.", 400);
    } else {
      error = new AppError(`데이터베이스 오류: ${pgError.message}`, 500);
    }
  }

  // JWT 에러 처리
  if (err.name === "JsonWebTokenError") {
    const message = "유효하지 않은 토큰입니다.";
    error = new AppError(message, 401);
  }

  if (err.name === "TokenExpiredError") {
    const message = "토큰이 만료되었습니다.";
    error = new AppError(message, 401);
  }

  // 기본 상태 코드 설정
  const statusCode = (error as AppError).statusCode || 500;
  const message = error.message || "서버 내부 오류가 발생했습니다.";

  // 에러 로깅
  logger.error({
    message: error.message,
    stack: error.stack,
    url: req.url,
    method: req.method,
    ip: req.ip,
    userAgent: req.get("User-Agent"),
  });

  // 응답 전송
  res.status(statusCode).json({
    success: false,
    message: message,
    error: {
      message: message,
      ...(process.env.NODE_ENV === "development" && { stack: error.stack }),
    },
  });
};

// 404 에러 핸들러
export const notFoundHandler = (req: Request, res: Response): void => {
  res.status(404).json({
    success: false,
    error: {
      message: "요청한 리소스를 찾을 수 없습니다.",
      path: req.originalUrl,
    },
  });
};
