/**
 * Error Handling Module
 * 
 * This module provides custom error classes and error handling utilities
 * for the n8n MCP Server.
 */

import { McpError as SdkMcpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from './error-codes.js';

// Re-export McpError from SDK
export { McpError } from '@modelcontextprotocol/sdk/types.js';
// Re-export ErrorCode enum
export { ErrorCode } from './error-codes.js';

/**
 * n8n API Error class for handling errors from the n8n API
 */
export class N8nApiError extends SdkMcpError {
  constructor(message: string, statusCode?: number, details?: unknown) {
    // Map HTTP status codes to appropriate MCP error codes
    let errorCode = ErrorCode.InternalError;
    
    if (statusCode) {
      if (statusCode === 401 || statusCode === 403) {
        errorCode = ErrorCode.AuthenticationError;
      } else if (statusCode === 404) {
        errorCode = ErrorCode.NotFoundError;
      } else if (statusCode >= 400 && statusCode < 500) {
        errorCode = ErrorCode.InvalidRequest;
      }
    }
    
    super(errorCode, formatErrorMessage(message, statusCode, details));
  }
}

/**
 * Format an error message with status code and details
 */
function formatErrorMessage(message: string, statusCode?: number, details?: unknown): string {
  let formattedMessage = message;
  
  if (statusCode) {
    formattedMessage += ` (Status: ${statusCode})`;
  }
  
  if (details) {
    try {
      const detailsStr = typeof details === 'string' 
        ? details 
        : JSON.stringify(details, null, 2);
      formattedMessage += `\nDetails: ${detailsStr}`;
    } catch (error) {
      // Ignore JSON stringification errors
    }
  }
  
  return formattedMessage;
}

/**
 * Safely parse JSON response from n8n API
 * 
 * @param text Text to parse as JSON
 * @returns Parsed JSON object or null if parsing fails
 */
export function safeJsonParse(text: string): any {
  try {
    return JSON.parse(text);
  } catch (error) {
    return null;
  }
}

/**
 * Handle axios errors and convert them to N8nApiError
 * 
 * @param error Error object from axios
 * @param defaultMessage Default error message
 * @returns N8nApiError with appropriate details
 */
export function handleAxiosError(error: any, defaultMessage = 'n8n API request failed'): N8nApiError {
  // Handle axios error responses
  if (error.response) {
    const statusCode = error.response.status;
    const responseData = error.response.data;
    
    let errorMessage = defaultMessage;
    if (responseData && responseData.message) {
      errorMessage = responseData.message;
    }
    
    return new N8nApiError(errorMessage, statusCode, responseData);
  }
  
  // Handle request errors (e.g., network issues)
  if (error.request) {
    return new N8nApiError(
      'Network error connecting to n8n API', 
      undefined, 
      error.message
    );
  }
  
  // Handle other errors
  return new N8nApiError(error.message || defaultMessage);
}

/**
 * Extract a readable error message from an error object
 * 
 * @param error Error object
 * @returns Readable error message
 */
export function getErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    return error.message;
  }
  
  if (typeof error === 'string') {
    return error;
  }
  
  try {
    return JSON.stringify(error);
  } catch {
    return 'Unknown error';
  }
}
