/**
 * Error handling utilities for type-safe error processing
 */

/**
 * Clerk error structure
 */
interface ClerkError {
  errors?: Array<{
    message: string;
    code?: string;
  }>;
  message?: string;
}

/**
 * Type guard to check if error is a Clerk error
 */
function isClerkError(error: unknown): error is ClerkError {
  return (
    typeof error === "object" &&
    error !== null &&
    ("errors" in error || "message" in error)
  );
}

/**
 * Extract error message from unknown error type
 * Handles Clerk errors, standard Error objects, and unknown types
 *
 * @param error - The caught error
 * @param fallback - Fallback message if no message can be extracted
 * @returns Error message string
 */
export function getErrorMessage(
  error: unknown,
  fallback = "An unknown error occurred",
): string {
  // Handle Clerk errors with nested error array
  if (isClerkError(error)) {
    if (error.errors?.[0]?.message) {
      return error.errors[0].message;
    }
    if (error.message) {
      return error.message;
    }
  }

  // Handle standard Error objects
  if (error instanceof Error) {
    return error.message;
  }

  // Handle string errors
  if (typeof error === "string") {
    return error;
  }

  // Handle objects with message property
  if (
    typeof error === "object" &&
    error !== null &&
    "message" in error &&
    typeof (error as Record<string, unknown>).message === "string"
  ) {
    return (error as { message: string }).message;
  }

  // Fallback for unknown types
  return fallback;
}

/**
 * Get Clerk error code if available
 */
export function getClerkErrorCode(error: unknown): string | undefined {
  if (isClerkError(error) && error.errors?.[0]?.code) {
    return error.errors[0].code;
  }
  return undefined;
}

/**
 * Safely extract gymId from Clerk user's public metadata
 *
 * @param metadata - Clerk publicMetadata object
 * @returns gymId string or null if not found
 */
export function getGymIdFromMetadata(metadata: unknown): string | null {
  if (
    typeof metadata === "object" &&
    metadata !== null &&
    "gymId" in metadata &&
    typeof (metadata as Record<string, unknown>).gymId === "string"
  ) {
    return (metadata as { gymId: string }).gymId;
  }
  return null;
}
