import type { ErrorHandler } from "hono";
import type { ContentfulStatusCode } from "hono/utils/http-status";
import { createLogger } from "./logger.js";

const log = createLogger("error-handler");

// ── Error Codes ─────────────────────────────────────────────────────────────

export enum ErrorCode {
  BINARY_NOT_FOUND = "BINARY_NOT_FOUND",
  CONTAINER_MISSING = "CONTAINER_MISSING",
  SESSION_NOT_FOUND = "SESSION_NOT_FOUND",
  AUTH_FAILED = "AUTH_FAILED",
  VALIDATION_ERROR = "VALIDATION_ERROR",
  RATE_LIMITED = "RATE_LIMITED",
  INTERNAL_ERROR = "INTERNAL_ERROR",
  NOT_FOUND = "NOT_FOUND",
  CONFLICT = "CONFLICT",
}

// ── AppError Base Class ─────────────────────────────────────────────────────

export class AppError extends Error {
  constructor(
    public readonly code: ErrorCode,
    message: string,
    public readonly statusCode: number = 500,
    public readonly details?: unknown,
  ) {
    super(message);
    this.name = "AppError";
  }
}

// ── Convenience Factories ───────────────────────────────────────────────────

export function notFound(
  message: string,
  code: ErrorCode = ErrorCode.NOT_FOUND,
): AppError {
  return new AppError(code, message, 404);
}

export function validationError(
  message: string,
  details?: unknown,
): AppError {
  return new AppError(ErrorCode.VALIDATION_ERROR, message, 400, details);
}

export function unauthorized(message: string): AppError {
  return new AppError(ErrorCode.AUTH_FAILED, message, 401);
}

export function conflict(message: string): AppError {
  return new AppError(ErrorCode.CONFLICT, message, 409);
}

export function internalError(message: string, details?: unknown): AppError {
  return new AppError(ErrorCode.INTERNAL_ERROR, message, 500, details);
}

// ── Hono Error Handler ─────────────────────────────────────────────────────

export function errorHandler(): ErrorHandler {
  return (err, c) => {
    if (err instanceof AppError) {
      return c.json(
        {
          error: err.message,
          code: err.code,
          ...(err.details !== undefined ? { details: err.details } : {}),
        },
        err.statusCode as ContentfulStatusCode,
      );
    }

    // Unknown / unexpected error — log and return generic 500
    log.error({ err }, "Unhandled error");
    return c.json(
      { error: "Internal server error", code: ErrorCode.INTERNAL_ERROR },
      500,
    );
  };
}
