const ErrorFormatter = require('../utils/errorFormatter');
const config = require('../config.json');

module.exports = errorHandler;

function errorHandler(err, req, res, next) {
	// Convert string errors to Error objects
	let error = err;
	if (typeof err === 'string') {
		error = new Error(err);
		error.name = 'CustomError';
	}

	// Format error dengan detail lengkap
	const formattedError = ErrorFormatter.format(error, req);
	const statusCode = ErrorFormatter.getStatusCode(error);
	const userMessage = ErrorFormatter.getUserMessage(error);

	// Log error untuk debugging (hanya di development atau jika ada request context)
	const isDevelopment = config.backendConfig?.NODE_ENV === 'development';
	
	if (isDevelopment) {
		console.error('========================================');
		console.error('ERROR HANDLED');
		console.error('========================================');
		console.error('Type:', formattedError.error.type);
		console.error('Name:', formattedError.error.name);
		console.error('Message:', formattedError.error.message);
		if (formattedError.error.details) {
			console.error('Details:', JSON.stringify(formattedError.error.details, null, 2));
		}
		if (formattedError.error.location) {
			console.error('Location:', 
				`${formattedError.error.location.file}:${formattedError.error.location.line}:${formattedError.error.location.column}`
			);
		}
		if (formattedError.request) {
			console.error('Request:', formattedError.request.method, formattedError.request.url);
		}
		if (formattedError.error.stack) {
			console.error('Stack:', formattedError.error.stack);
		}
		console.error('========================================');
	} else {
		// Production: log minimal info
		console.error(`[${formattedError.error.type}] ${formattedError.error.message}`, {
			url: formattedError.request?.url,
			method: formattedError.request?.method,
			requestId: formattedError.request?.requestId,
		});
	}

	// Response untuk client
	// Di production, jangan kirim stack trace dan detail sensitif
	const response = {
		success: false,
		message: userMessage,
		error: {
			type: formattedError.error.type,
			message: formattedError.error.message,
		},
	};
	
	// ROBUST: Preserve error code if it exists (for token errors, etc.)
	if (error.code) {
		response.code = error.code;
	}

	// ROBUST: Preserve error code if it exists (for token errors, etc.) - always include in response
	if (error.code) {
		response.code = error.code;
	}
	
	// Add details hanya jika validation error (safe untuk client)
	if (formattedError.error.details && 
		(formattedError.error.type === 'VALIDATION_ERROR' || 
		 formattedError.error.type === 'UNIQUE_CONSTRAINT_ERROR' ||
		 formattedError.error.type === 'FOREIGN_KEY_ERROR')) {
		response.error.details = formattedError.error.details;
	}

	// Add helpful information for payload too large error
	if (formattedError.error.type === 'PAYLOAD_TOO_LARGE_ERROR') {
		response.error.details = {
			type: 'payload_too_large',
			message: 'The request body exceeds the maximum allowed size',
			maxSize: '50MB',
			suggestion: 'Please split your import into smaller batches or reduce the number of items per request',
		};
	}

	// Di development, tambahkan info lebih lengkap
	if (isDevelopment) {
		response.error.name = formattedError.error.name;
		if (formattedError.error.location) {
			response.error.location = formattedError.error.location;
		}
		if (formattedError.error.code) {
			response.error.code = formattedError.error.code;
		}
		// Stack trace hanya di development
		if (formattedError.error.stack) {
			response.error.stack = formattedError.error.stack;
		}
		// Request context untuk debugging
		if (formattedError.request) {
			response.request = formattedError.request;
		}
	}

	// Add request ID untuk tracking
	if (formattedError.request?.requestId) {
		response.requestId = formattedError.request.requestId;
	}

	// 503: Retry-After dari config.backendConfig.retryAfterSeconds (default 30)
	if (statusCode === 503) {
		res.set("Retry-After", String(config.backendConfig?.retryAfterSeconds ?? 30));
	}

	return res.status(statusCode).json(response);
}
