/**
 * Base Error Types and Utilities
 *
 * Provides type-safe error handling for API routes
 * Eliminates the need for 'error: any' patterns
 */

/**
 * Base error interface for all application errors
 */
export interface BaseError {
  message: string;
  code?: string;
  statusCode?: number;
  stack?: string;
}

/**
 * Type guard to check if an error is an Error instance
 */
export function isError(error: unknown): error is Error {
  return error instanceof Error;
}

/**
 * Type guard to check if an error has a message property
 */
export function hasMessage(error: unknown): error is { message: string } {
  return (
    typeof error === "object" &&
    error !== null &&
    "message" in error &&
    typeof (error as { message: unknown }).message === "string"
  );
}

/**
 * Type guard to check if an error has a code property
 */
export function hasCode(error: unknown): error is { code: string } {
  return (
    typeof error === "object" &&
    error !== null &&
    "code" in error &&
    typeof (error as { code: unknown }).code === "string"
  );
}

/**
 * Type guard to check if an error has a status/statusCode property
 */
export function hasStatusCode(error: unknown): error is { statusCode: number } {
  return (
    typeof error === "object" &&
    error !== null &&
    ("statusCode" in error || "status" in error) &&
    (typeof (error as { statusCode?: unknown }).statusCode === "number" ||
      typeof (error as { status?: unknown }).status === "number")
  );
}

/**
 * Safely extract error message from unknown error
 */
export function getErrorMessage(error: unknown): string {
  if (isError(error)) {
    return error.message;
  }
  if (hasMessage(error)) {
    return error.message;
  }
  if (typeof error === "string") {
    return error;
  }
  return "An unknown error occurred";
}

/**
 * Safely extract error code from unknown error
 */
export function getErrorCode(error: unknown): string | undefined {
  if (hasCode(error)) {
    return error.code;
  }
  return undefined;
}

/**
 * Safely extract status code from unknown error
 */
export function getStatusCode(error: unknown): number | undefined {
  if (hasStatusCode(error)) {
    return (
      (error as { statusCode?: number; status?: number }).statusCode ||
      (error as { statusCode?: number; status?: number }).status
    );
  }
  return undefined;
}

/**
 * Safely extract stack trace from unknown error
 */
export function getErrorStack(error: unknown): string | undefined {
  if (isError(error)) {
    return error.stack;
  }
  if (
    typeof error === "object" &&
    error !== null &&
    "stack" in error &&
    typeof (error as { stack: unknown }).stack === "string"
  ) {
    return (error as { stack: string }).stack;
  }
  return undefined;
}

/**
 * Convert unknown error to BaseError
 */
export function toBaseError(error: unknown): BaseError {
  return {
    message: getErrorMessage(error),
    code: getErrorCode(error),
    statusCode: getStatusCode(error),
    stack: getErrorStack(error),
  };
}

/**
 * Application-specific error class
 */
export class ApplicationError extends Error {
  constructor(
    message: string,
    public readonly code?: string,
    public readonly statusCode: number = 500,
    public readonly details?: Record<string, unknown>,
  ) {
    super(message);
    this.name = "ApplicationError";

    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, ApplicationError);
    }
  }

  toJSON() {
    return {
      name: this.name,
      message: this.message,
      code: this.code,
      statusCode: this.statusCode,
      details: this.details,
    };
  }
}

/**
 * Validation error class
 */
export class ValidationError extends ApplicationError {
  constructor(message: string, details?: Record<string, unknown>) {
    super(message, "VALIDATION_ERROR", 400, details);
    this.name = "ValidationError";
  }
}

/**
 * Authentication error class
 */
export class AuthenticationError extends ApplicationError {
  constructor(message: string, details?: Record<string, unknown>) {
    super(message, "AUTHENTICATION_ERROR", 401, details);
    this.name = "AuthenticationError";
  }
}

/**
 * Authorization error class
 */
export class AuthorizationError extends ApplicationError {
  constructor(message: string, details?: Record<string, unknown>) {
    super(message, "AUTHORIZATION_ERROR", 403, details);
    this.name = "AuthorizationError";
  }
}

/**
 * Not found error class
 */
export class NotFoundError extends ApplicationError {
  constructor(message: string, details?: Record<string, unknown>) {
    super(message, "NOT_FOUND", 404, details);
    this.name = "NotFoundError";
  }
}

/**
 * Database error class
 */
export class DatabaseError extends ApplicationError {
  constructor(message: string, details?: Record<string, unknown>) {
    super(message, "DATABASE_ERROR", 500, details);
    this.name = "DatabaseError";
  }
}

/**
 * External API error class
 */
export class ExternalAPIError extends ApplicationError {
  constructor(
    message: string,
    public readonly service: string,
    details?: Record<string, unknown>,
  ) {
    super(message, "EXTERNAL_API_ERROR", 502, details);
    this.name = "ExternalAPIError";
  }

  toJSON() {
    return {
      ...super.toJSON(),
      service: this.service,
    };
  }
}
