// helpers/errorHandler.ts
import {
	IExecuteFunctions,
	NodeApiError,
	NodeOperationError,
	INodeExecutionData,
} from 'n8n-workflow';
import { logger } from './logger';

/**
 * Handle API errors from Aruba Central
 *
 * @param this The n8n execution context
 * @param error The error that was caught
 * @param message Optional custom error message
 * @returns Never completes normally, always throws an error
 */
export function handleApiError(this: IExecuteFunctions, error: any, message?: string): never {
	logger.error('error:api', { originalMessage: error.message, customMessage: message });

	// Special handling for rate limiting errors
	if (error.message && error.message.includes('rate limit')) {
		let retryAfter = 'unknown time';

		// Try to extract the retry time from the error message
		const retryMatch = error.message.match(/(\d+) seconds/);
		if (retryMatch && retryMatch[1]) {
			retryAfter = `${retryMatch[1]} seconds`;
		}

		const rateMessage = `API rate limited. Please retry after ${retryAfter}.`;
		logger.error('error:ratelimit', rateMessage);
		throw new NodeOperationError(this.getNode(), rateMessage);
	}

	if (error.response?.body) {
		const errorBody = error.response.body;
		let errorMessage = message || 'Unknown error';

		// Check for rate limiting in the response body
		if (
			typeof errorBody === 'object' &&
			errorBody.message &&
			errorBody.message.includes('rate limit')
		) {
			let retryAfter = 'unknown time';

			// Try to extract the retry time from the message
			const retryMatch = errorBody.message.match(/(\d+) seconds/);
			if (retryMatch && retryMatch[1]) {
				retryAfter = `${retryMatch[1]} seconds`;
			}

			const rateMessage = `API rate limited. Please retry after ${retryAfter}.`;
			logger.error('error:ratelimit', rateMessage);
			throw new NodeOperationError(this.getNode(), rateMessage);
		}

		// Process other types of error messages
		if (typeof errorBody === 'object') {
			if (errorBody.description) {
				errorMessage = errorBody.description;
			} else if (errorBody.error_description) {
				errorMessage = errorBody.error_description;
			} else if (errorBody.message) {
				errorMessage = errorBody.message;
			} else if (errorBody.detail) {
				errorMessage = errorBody.detail;
			}
		} else if (typeof errorBody === 'string') {
			try {
				const parsedBody = JSON.parse(errorBody);
				if (parsedBody.message) {
					errorMessage = parsedBody.message;
				}
			} catch (e) {
				// If parsing fails, use the string directly if it's not too long
				if (errorBody.length < 300) {
					errorMessage = errorBody;
				}
			}
		}

		logger.error('error:api', `Throwing NodeApiError with message: ${errorMessage}`);
		throw new NodeApiError(this.getNode(), error, { message: errorMessage });
	}

	if (message) {
		logger.error('error:operation', `Throwing NodeOperationError with message: ${message}`);
		throw new NodeOperationError(this.getNode(), message);
	}

	logger.error('error:unknown', 'Re-throwing original error');
	throw error;
}

/**
 * Handle validation errors
 *
 * @param this The n8n execution context
 * @param message Error message describing the validation failure
 * @returns Never completes normally, always throws an error
 */
export function handleValidationError(this: IExecuteFunctions, message: string): never {
	logger.error('error:validation', message);
	throw new NodeOperationError(this.getNode(), message);
}

/**
 * Handle API errors while allowing execution to continue
 *
 * @param this The n8n execution context
 * @param error The error that was caught
 * @param message Optional custom error message
 * @returns Array with a single item containing error details
 */
export function handleApiErrorWithContinue(
	this: IExecuteFunctions,
	error: any,
	message?: string,
): INodeExecutionData[] {
	logger.error('error:api:continue', { originalMessage: error.message, customMessage: message });

	// Special handling for rate limiting errors
	let errorMessage = message || error.message || 'Unknown error occurred';

	// Check for rate limiting in the error message
	if (error.message && error.message.includes('rate limit')) {
		let retryAfter = 'unknown time';

		// Try to extract the retry time from the error message
		const retryMatch = error.message.match(/(\d+) seconds/);
		if (retryMatch && retryMatch[1]) {
			retryAfter = `${retryMatch[1]} seconds`;
		}

		errorMessage = `API rate limited. Please retry after ${retryAfter}.`;
		logger.error('error:ratelimit', errorMessage);
	}

	// If continueOnFail is enabled, return error as data
	if (this.continueOnFail()) {
		logger.debug('error:api:continue', `Continuing execution with error: ${errorMessage}`);

		return [
			{
				json: {
					success: false,
					error: errorMessage,
					details: error.response?.body || {},
				},
			},
		];
	}

	// Otherwise handle as regular error (will throw)
	return handleApiError.call(this, error, errorMessage) as never;
}
