/* eslint-disable no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-console */
import { Reporter, TestCase, TestResult, FullConfig, Suite, FullResult, TestError } from '@playwright/test/reporter';
import { relative } from 'path';

/**
 * ========================================================================================
 * REPORTER PERSONALIZADO
 * ========================================================================================
 * 
 * Este reporter personalizado proporciona una salida detallada y estructurada de las 
 * pruebas de Playwright, con manejo especializado para diferentes tipos de errores
 * y un formato similar al reporter "list" nativo pero con características adicionales.
 * 
 * Características principales:
 * - Detección automática de errores de selectores y timeouts
 * - Resaltado de líneas importantes en stack traces
 * - Manejo de errores globales y de configuración
 * - Estadísticas detalladas y tasa de éxito
 * 
 * ========================================================================================
 */

// ========================================================================================
// TYPES & INTERFACES
// ========================================================================================

/**
 * Información de un test que ha fallado
 */
interface FailedTestInfo {
	/** Título completo del test */
	readonly title: string;
	/** Mensaje de error (si está disponible) */
	readonly error?: string;
	/** Ubicación del archivo del test */
	readonly location?: string;
	/** Duración del test en segundos */
	readonly duration?: number;
}

/**
 * Estadísticas de ejecución de tests
 */
interface TestStats {
	/** Número de tests que pasaron */
	passed: number;
	/** Número de tests que fallaron */
	failed: number;
	/** Número de tests omitidos */
	skipped: number;
}

/**
 * Información de tiempo de ejecución
 */
interface TimeInfo {
	/** Minutos transcurridos */
	readonly minutes: number;
	/** Segundos transcurridos (resto) */
	readonly seconds: number;
	/** Total de segundos transcurridos */
	readonly totalSeconds: number;
}

/**
 * Tipos de errores que puede detectar el reporter
 */
type ErrorType = 'timeout' | 'selector' | 'element' | 'business' | 'expect' | 'unknown';

// ========================================================================================
// ENUMS & CONSTANTS
// ========================================================================================

/**
 * Estados posibles de un test en Playwright
 */
enum TestStatus {
	PASSED = 'passed',
	FAILED = 'failed',
	SKIPPED = 'skipped',
	TIMED_OUT = 'timedOut'
}

/**
 * Patrones de texto para detectar diferentes tipos de errores
 */
const ERROR_PATTERNS: Record<ErrorType, readonly string[]> = {
	/** Errores relacionados con timeouts */
	timeout: ['Test timeout', 'timeout', 'exceeded'] as const,
	/** Errores relacionados con selectores y locators */
	selector: ['locator.', 'waiting for', 'Locator', 'getByText', 'getBy', 'selector'] as const,
	/** Errores relacionados con elementos no encontrados */
	element: ['not found', 'not visible', 'not attached'] as const,
	/** Errores de assertions/expect */
	expect: [
		'expect(', 'toBeVisible', 'toHaveText', 'toHaveValue', 'toBeChecked', 'toBeEnabled', 
		'toHaveURL', 'toHaveTitle', 'toContainText', 'toBe', 'toEqual', 'toBeDisabled',
		'toBeEditable', 'toBeEmpty', 'toBeHidden', 'toHaveAttribute', 'toHaveClass',
		'toHaveCSS', 'toHaveId', 'toHaveJSProperty', 'toHaveScreenshot', 'toHaveValues',
		'toBeAttached', 'toBeInViewport', 'toHaveAccessibleDescription', 'toHaveAccessibleName',
		'toHaveRole', 'toBeChecked', 'toBeDisabled', 'toBeEditable', 'toBeEmpty', 'toBeEnabled',
		'toBeHidden', 'toBeVisible', 'toBeFocused'
	] as const,
	/** Errores de lógica de negocio (sin patrones específicos) */
	business: [] as const,
	/** Errores desconocidos */
	unknown: [] as const
} as const;

/**
 * Patrones para resaltar líneas importantes en el stack trace
 * Estas líneas contienen información crucial sobre qué selector o acción falló
 */
const STACK_HIGHLIGHT_PATTERNS = [
	'waiting for',
	'locator.',
	'getByText',
	'getBy',
	'click',
	'fill'
] as const;

/**
 * Símbolos de consola para mejorar la legibilidad de la salida
 */
const CONSOLE_SYMBOLS = {
	SUCCESS: '✅',
	ERROR: '❌',
	SKIP: '⏩',
	WARNING: '⚠️',
	GLOBAL_ERROR: '🚨',
	STATS: '📊',
	LOCATION: '📍',
	TIME: '⏱️',
	SUCCESS_RATE: '🎯',
	STATUS: '📌',
	DETAIL: '🔍',
	ROCKET: '🚀',
	SPARKLES: '✨'
} as const;

// ========================================================================================
// MAIN REPORTER CLASS
// ========================================================================================

/**
 * Reporter personalizado que proporciona salida detallada
 * con manejo especializado de diferentes tipos de errores
 */
class customReporter implements Reporter {
	/** Estadísticas de ejecución de tests */
	private readonly stats: TestStats = { passed: 0, failed: 0, skipped: 0 };
	
	/** Lista de tests que han fallado con información detallada */
	private readonly failedTests: FailedTestInfo[] = [];
	
	/** Número del test actual (para mostrar progreso) */
	private currentTestNumber = 0;
	
	/** Número total de tests a ejecutar */
	private totalTests = 0;
	
	/** Timestamp de inicio de la ejecución */
	private readonly startTime: number = Date.now();

	// ========================================================================================
	// PUBLIC REPORTER METHODS - Métodos requeridos por la interfaz Reporter
	// ========================================================================================

	/**
	 * Se ejecuta al inicio de la suite de tests
	 * @param config - Configuración de Playwright
	 * @param suite - Suite de tests a ejecutar
	 */
	onBegin(config: FullConfig, suite: Suite): void {
		void config;
		this.totalTests = suite.allTests().length;
		this.logInitialMessage();
	}

	/**
	 * Se ejecuta cuando un test individual comienza
	 * @param test - Información del test que está comenzando
	 */
	onTestBegin(test: TestCase): void {
		this.currentTestNumber++;
		const testInfo = this.extractTestInfo(test);
		this.logTestStart(testInfo);
	}

	/**
	 * Se ejecuta cuando un test individual termina
	 * @param test - Información del test que terminó
	 * @param result - Resultado del test (passed, failed, skipped, etc.)
	 */
	onTestEnd(test: TestCase, result: TestResult): void {
		const duration = this.calculateDuration(result.duration);
		
		// Solo mostrar debug en modo desarrollo
		if (process.env.NODE_ENV === 'development') {
			this.logDebugInfo(result);
		}

		switch (result.status as TestStatus) {
		case TestStatus.PASSED:
			this.handlePassedTest(duration);
			break;
		case TestStatus.FAILED:
			this.handleFailedTest(test, result, duration);
			break;
		case TestStatus.SKIPPED:
			this.handleSkippedTest();
			break;
		case TestStatus.TIMED_OUT:
			this.handleTimedOutTest(duration);
			break;
		default:
			this.handleUnknownStatus(result);
			break;
		}
	}

	/**
	 * Se ejecuta cuando ocurre un error global (no específico de un test)
	 * @param error - Error global que ocurrió
	 */
	onError(error: TestError): void {
		this.logGlobalError(error);
	}

	/**
	 * Se ejecuta al final de toda la suite de tests
	 * @param result - Resultado final de la ejecución
	 */
	onEnd(result: FullResult): void {
		const timeInfo = this.calculateTimeInfo();
		this.logFinalSummary(result, timeInfo);
	}

	// ========================================================================================
	// PRIVATE HELPER METHODS - Métodos auxiliares para organizar la lógica
	// ========================================================================================

	/**
	 * Muestra el mensaje inicial cuando comienzan las pruebas
	 */
	private logInitialMessage(): void {
		console.log(`\n=== ${CONSOLE_SYMBOLS.ROCKET} INICIANDO PRUEBAS ===`);
		console.log('=== Por favor no toque el PC, hasta que terminen las pruebas, si no explotamos todos ===');
		console.log(`📋 Total de pruebas a ejecutar: ${this.totalTests}`);
		console.log('==========================================\n');
	}

	/**
	 * Extrae información relevante de un test para mostrar en la consola
	 * @param test - Test del cual extraer información
	 * @returns Objeto con información formateada del test
	 */
	private extractTestInfo(test: TestCase): { browser: string; location: string; line: string; column: string; fullTitle: string } {
		// Obtener el nombre real del proyecto desde la configuración
		const projectName = test.parent?.project?.name || 'unknown';
		const realProjectName = projectName === 'project' ? 'pos-admin' : projectName;
		
		const location = test.location?.file ? relative(process.cwd(), test.location.file) : 'Unknown location';
		const line = test.location?.line?.toString() || '?';
		const column = test.location?.column?.toString() || '?';

		// Construir el título completo del test incluyendo describe y test
		const fullTitle = this.buildFullTestTitle(test);

		return { browser: realProjectName, location, line, column, fullTitle };
	}

	/**
	 * Construye el título completo del test incluyendo todos los describe anidados
	 * @param test - Test del cual extraer el título
	 * @returns Título completo del test
	 */
	private buildFullTestTitle(test: TestCase): string {
		const titles: string[] = [];
		let current: any = test.parent;

		// Recorrer hacia arriba para obtener todos los describe
		while (current && current.title) {
			titles.unshift(current.title);
			current = current.parent;
		}

		// Agregar el título del test al final
		titles.push(test.title);

		return titles.join(' › ');
	}

	/**
	 * Muestra información del test que está comenzando
	 * @param testInfo - Información del test formateada
	 */
	private logTestStart(testInfo: { browser: string; location: string; line: string; column: string; fullTitle: string }): void {
		console.log(`\n${this.currentTestNumber}) [${testInfo.browser}] › ${testInfo.location}:${testInfo.line}:${testInfo.column} › ${testInfo.fullTitle}`);
	}

	/**
	 * Calcula la duración de un test en segundos
	 * @param durationMs - Duración en milisegundos
	 * @returns Objeto con duración en segundos y formato string
	 */
	private calculateDuration(durationMs: number): { seconds: number; formatted: string } {
		const seconds = durationMs / 1000;
		return {
			seconds,
			formatted: seconds.toFixed(2)
		};
	}

	/**
	 * Muestra información de debug sobre el resultado del test
	 * @param result - Resultado del test
	 */
	private logDebugInfo(result: TestResult): void {
		const statusMessages = {
			passed: '✅ Completado exitosamente',
			failed: '❌ Falló durante la ejecución',
			skipped: '⏩ Omitido',
			timedOut: '⏰ Tiempo excedido'
		};

		const statusMessage = statusMessages[result.status as keyof typeof statusMessages] || `⚠️ Estado: ${result.status}`;
		console.log(`   ${statusMessage}`);
		
		if (result.error && result.status === 'failed') {
			console.log(`   💬 Razón: ${result.error.message}`);
		}
	}

	/**
	 * Maneja un test que pasó exitosamente
	 * @param duration - Información de duración del test
	 */
	private handlePassedTest(duration: { formatted: string }): void {
		this.stats.passed++;
		console.log(`   ${CONSOLE_SYMBOLS.SUCCESS} Pasó (${duration.formatted}s)`);
	}

	/**
	 * Maneja un test que falló
	 * @param test - Información del test que falló
	 * @param result - Resultado del test fallido
	 * @param duration - Información de duración del test
	 */
	private handleFailedTest(test: TestCase, result: TestResult, duration: { seconds: number; formatted: string }): void {
		this.stats.failed++;
		
		const location = test.location?.file ? relative(process.cwd(), test.location.file) : 'Unknown location';
		const fullTitle = this.buildFullTestTitle(test);
		this.addFailedTest(fullTitle, result.error?.message, location, duration.seconds);

		const errorType = this.detectErrorType(result.error?.message || '');
		this.logFailedTest(errorType, duration.formatted, test.timeout);

		if (result.error) {
			this.logErrorDetails(result.error, errorType);
		} else if (this.hasMultipleErrors(result)) {
			this.logMultipleErrors(result);
		} else {
			this.logUnknownError();
		}
	}

	/**
	 * Maneja un test que fue omitido
	 */
	private handleSkippedTest(): void {
		this.stats.skipped++;
		console.log(`   ${CONSOLE_SYMBOLS.SKIP} Omitido`);
	}

	/**
	 * Maneja un test que excedió el tiempo límite
	 * @param duration - Información de duración del test
	 */
	private handleTimedOutTest(duration: { formatted: string }): void {
		this.stats.failed++;
		console.log(`\n   ${CONSOLE_SYMBOLS.ERROR} Test timeout (${duration.formatted}s)\n`);
		console.error(`   Error: Test excedió el tiempo límite`);
	}

	/**
	 * Maneja un test con estado desconocido
	 * @param result - Resultado del test con estado desconocido
	 */
	private handleUnknownStatus(result: TestResult): void {
		console.log(`   ${CONSOLE_SYMBOLS.WARNING} Status desconocido: ${result.status}`);
		if (result.error) {
			console.error(`   Error: ${result.error.message}`);
			if (result.error.stack) {
				console.error(`   Stack: ${result.error.stack}`);
			}
		}
	}

	/**
	 * Agrega un test fallido a la lista para el resumen final
	 * @param title - Título del test
	 * @param error - Mensaje de error (opcional)
	 * @param location - Ubicación del archivo (opcional)
	 * @param duration - Duración en segundos (opcional)
	 */
	private addFailedTest(title: string, error?: string, location?: string, duration?: number): void {
		this.failedTests.push({ title, error, location, duration });
	}

	/**
	 * Detecta el tipo de error basado en el mensaje
	 * @param errorMessage - Mensaje de error a analizar
	 * @returns Tipo de error detectado
	 */
	private detectErrorType(errorMessage: string): ErrorType {
		for (const [type, patterns] of Object.entries(ERROR_PATTERNS)) {
			if (patterns.some(pattern => errorMessage.includes(pattern))) {
				return type as ErrorType;
			}
		}
		return 'business';
	}

	/**
	 * Muestra el mensaje apropiado para un test fallido según el tipo de error
	 * @param errorType - Tipo de error detectado
	 * @param durationFormatted - Duración formateada como string
	 * @param testTimeout - Timeout configurado para el test (opcional)
	 */
	private logFailedTest(errorType: ErrorType, durationFormatted: string, testTimeout?: number): void {
		const messages: Record<ErrorType, string> = {
			timeout: `\n   ${CONSOLE_SYMBOLS.ERROR} Test timeout of ${testTimeout || 30000}ms exceeded.\n`,
			selector: `\n   ${CONSOLE_SYMBOLS.ERROR} Selector/Element error (${durationFormatted}s)\n`,
			element: `\n   ${CONSOLE_SYMBOLS.ERROR} Selector/Element error (${durationFormatted}s)\n`,
			expect: `\n   ${CONSOLE_SYMBOLS.ERROR} Assertion failed (${durationFormatted}s)\n`,
			business: `\n   ${CONSOLE_SYMBOLS.ERROR} Test falló (${durationFormatted}s)\n`,
			unknown: `\n   ${CONSOLE_SYMBOLS.ERROR} Test falló (${durationFormatted}s)\n`
		};

		console.log(messages[errorType]);
	}

	/**
	 * Muestra los detalles de un error específico
	 * @param error - Error a mostrar
	 * @param errorType - Tipo de error para formateo especial
	 */
	private logErrorDetails(error: TestError, errorType: ErrorType): void {
		console.error(`   Error: ${error.message || 'Sin mensaje de error'}`);
		
		// Extraer y mostrar el selector que falló
		const failedSelector = this.extractFailedSelector(error.message || '', error.stack || '');
		if (failedSelector) {
			console.error(`   🎯 Selector que falló: ${failedSelector}`);
		}
		
		if (error.stack) {
			console.error('\n   Call log:');
			this.logStackTrace(error.stack, errorType);
		}
	}

	/**
	 * Extrae el selector específico que falló del mensaje de error o stack trace
	 * @param errorMessage - Mensaje de error
	 * @param stackTrace - Stack trace completo
	 * @returns El selector que falló o null si no se puede determinar
	 */
	private extractFailedSelector(errorMessage: string, stackTrace: string): string | null {
		// Patrones para extraer TODOS los selectores de Playwright
		const selectorPatterns = [
			// Todos los métodos getBy* de Playwright
			{ pattern: /waiting for getByText\('([^']+)'\)/, method: 'getByText' },
			{ pattern: /waiting for getByText\("([^"]+)"\)/, method: 'getByText' },
			{ pattern: /waiting for getByRole\('([^']+)',\s*\{\s*name:\s*'([^']+)'\s*\}\)/, method: 'getByRole' },
			{ pattern: /waiting for getByRole\("([^"]+)",\s*\{\s*name:\s*"([^"]+)"\s*\}\)/, method: 'getByRole' },
			{ pattern: /waiting for getByRole\('([^']+)'\)/, method: 'getByRole' },
			{ pattern: /waiting for getByRole\("([^"]+)"\)/, method: 'getByRole' },
			{ pattern: /waiting for getByPlaceholder\('([^']+)'\)/, method: 'getByPlaceholder' },
			{ pattern: /waiting for getByPlaceholder\("([^"]+)"\)/, method: 'getByPlaceholder' },
			{ pattern: /waiting for getByTestId\('([^']+)'\)/, method: 'getByTestId' },
			{ pattern: /waiting for getByTestId\("([^"]+)"\)/, method: 'getByTestId' },
			{ pattern: /waiting for getByLabel\('([^']+)'\)/, method: 'getByLabel' },
			{ pattern: /waiting for getByLabel\("([^"]+)"\)/, method: 'getByLabel' },
			{ pattern: /waiting for getByAltText\('([^']+)'\)/, method: 'getByAltText' },
			{ pattern: /waiting for getByAltText\("([^"]+)"\)/, method: 'getByAltText' },
			{ pattern: /waiting for getByTitle\('([^']+)'\)/, method: 'getByTitle' },
			{ pattern: /waiting for getByTitle\("([^"]+)"\)/, method: 'getByTitle' },
			
			// Para selectores CSS, XPath y otros
			{ pattern: /waiting for locator\('([^']+)'\)/, method: 'locator' },
			{ pattern: /waiting for locator\("([^"]+)"\)/, method: 'locator' },
			{ pattern: /locator\('([^']+)'\)/, method: 'locator' },
			{ pattern: /locator\("([^"]+)"\)/, method: 'locator' },
			
			// Para frameLocator
			{ pattern: /waiting for frameLocator\('([^']+)'\)/, method: 'frameLocator' },
			{ pattern: /waiting for frameLocator\("([^"]+)"\)/, method: 'frameLocator' },

			// Para errores de expect/assertions con todos los getBy*
			{ pattern: /expect\(.*?getByText\('([^']+)'\)\)/, method: 'getByText' },
			{ pattern: /expect\(.*?getByText\("([^"]+)"\)\)/, method: 'getByText' },
			{ pattern: /expect\(.*?getByRole\('([^']+)',\s*\{\s*name:\s*'([^']+)'\s*\}\)\)/, method: 'getByRole' },
			{ pattern: /expect\(.*?getByRole\('([^']+)'\)\)/, method: 'getByRole' },
			{ pattern: /expect\(.*?getByTestId\('([^']+)'\)\)/, method: 'getByTestId' },
			{ pattern: /expect\(.*?getByLabel\('([^']+)'\)\)/, method: 'getByLabel' },
			{ pattern: /expect\(.*?getByPlaceholder\('([^']+)'\)\)/, method: 'getByPlaceholder' },
			{ pattern: /expect\(.*?getByAltText\('([^']+)'\)\)/, method: 'getByAltText' },
			{ pattern: /expect\(.*?getByTitle\('([^']+)'\)\)/, method: 'getByTitle' },
			{ pattern: /expect\(.*?locator\('([^']+)'\)\)/, method: 'locator' },
		];

		// Intentar extraer del mensaje de error primero
		for (const { pattern, method } of selectorPatterns) {
			const match = errorMessage.match(pattern);
			if (match) {
				if (match[2] && method === 'getByRole') {
					// Para casos como getByRole con name
					if (errorMessage.includes('expect(')) {
						return `expect(page.getByRole('${match[1]}', { name: '${match[2]}' }))`;
					}
					return `page.getByRole('${match[1]}', { name: '${match[2]}' })`;
				}
				// Si es un error de expect, mostrar con expect()
				if (errorMessage.includes('expect(')) {
					return `expect(page.${method}('${match[1]}'))`;
				}
				return `page.${method}('${match[1]}')`;
			}
		}

		// Si no se encuentra en el mensaje, buscar en el stack trace
		const stackLines = stackTrace.split('\n');
		for (const line of stackLines) {
			// Buscar líneas que contengan información del selector
			if (line.includes('waiting for') || line.includes('locator(') || line.includes('expect(')) {
				for (const { pattern, method } of selectorPatterns) {
					const match = line.match(pattern);
					if (match) {
						if (match[2] && method === 'getByRole') {
							if (line.includes('expect(')) {
								return `expect(page.getByRole('${match[1]}', { name: '${match[2]}' }))`;
							}
							return `page.getByRole('${match[1]}', { name: '${match[2]}' })`;
						}
						if (line.includes('expect(')) {
							return `expect(page.${method}('${match[1]}'))`;
						}
						return `page.${method}('${match[1]}')`;
					}
				}
			}
		}

		return null;
	}

	/**
	 * Muestra el stack trace con resaltado especial para errores de selector
	 * @param stack - Stack trace completo
	 * @param errorType - Tipo de error para determinar si resaltar líneas
	 */
	private logStackTrace(stack: string, errorType: ErrorType): void {
		const stackLines = stack.split('\n');
		const shouldHighlight = errorType === 'selector' || errorType === 'element';

		stackLines.forEach(line => {
			if (!line.trim()) return;

			if (shouldHighlight && this.shouldHighlightLine(line)) {
				console.error(`     - ${line.trim()}`);
			} else {
				console.error(`      ${line.trim()}`);
			}
		});
	}

	/**
	 * Determina si una línea del stack trace debe ser resaltada
	 * @param line - Línea del stack trace a evaluar
	 * @returns true si la línea debe ser resaltada
	 */
	private shouldHighlightLine(line: string): boolean {
		return STACK_HIGHLIGHT_PATTERNS.some(pattern => line.includes(pattern));
	}

	/**
	 * Verifica si un resultado tiene múltiples errores
	 * @param result - Resultado del test a verificar
	 * @returns true si tiene múltiples errores
	 */
	private hasMultipleErrors(result: TestResult): boolean {
		return Array.isArray((result as any).errors) && (result as any).errors.length > 0;
	}

	/**
	 * Muestra múltiples errores de un test
	 * @param result - Resultado del test con múltiples errores
	 */
	private logMultipleErrors(result: TestResult): void {
		const errors = (result as any).errors as any[];
		errors.forEach((err: any, idx: number) => {
			console.error(`   [${idx + 1}] Error: ${err.message || err}`);
			if (err.stack) {
				console.error('\n   Call log:');
				this.logStackTrace(err.stack, 'unknown');
			}
		});
	}

	/**
	 * Muestra mensaje para errores desconocidos
	 */
	private logUnknownError(): void {
		console.error(`   ${CONSOLE_SYMBOLS.ERROR} Error desconocido - No se pudo obtener información del error`);
	}

	/**
	 * Muestra información de errores globales
	 * @param error - Error global que ocurrió
	 */
	private logGlobalError(error: TestError): void {
		console.error(`\n${CONSOLE_SYMBOLS.GLOBAL_ERROR} ERROR GLOBAL DETECTADO:`);
		console.error(`   Mensaje: ${error.message || 'Sin mensaje'}`);
		
		if (error.stack) {
			console.error('\n   Stack trace:');
			this.logStackTrace(error.stack, 'unknown');
		}
		console.error('');
	}

	/**
	 * Calcula información de tiempo transcurrido
	 * @returns Objeto con información de tiempo formateada
	 */
	private calculateTimeInfo(): TimeInfo {
		const totalSeconds = (Date.now() - this.startTime) / 1000;
		const minutes = Math.floor(totalSeconds / 60);
		const seconds = Math.floor(totalSeconds % 60);

		return { minutes, seconds, totalSeconds };
	}

	/**
	 * Calcula la tasa de éxito de los tests
	 * @returns Porcentaje de éxito (0-100)
	 */
	private calculateSuccessRate(): number {
		const totalExecuted = this.totalTests - this.stats.skipped;
		return totalExecuted > 0 ? (this.stats.passed / totalExecuted) * 100 : 0;
	}

	/**
	 * Muestra el resumen final de la ejecución
	 * @param result - Resultado final de la suite
	 * @param timeInfo - Información de tiempo transcurrido
	 */
	private logFinalSummary(result: FullResult, timeInfo: TimeInfo): void {
		console.log(`\n=== ${CONSOLE_SYMBOLS.STATS} RESUMEN FINAL ===`);
		console.log(`${CONSOLE_SYMBOLS.SUCCESS} Pruebas exitosas: ${this.stats.passed}`);
		console.log(`${CONSOLE_SYMBOLS.ERROR} Pruebas fallidas: ${this.stats.failed}`);
		console.log(`${CONSOLE_SYMBOLS.SKIP} Pruebas omitidas: ${this.stats.skipped}`);
		console.log(`${CONSOLE_SYMBOLS.TIME} Tiempo total: ${timeInfo.minutes}m ${timeInfo.seconds}s`);
		console.log(`${CONSOLE_SYMBOLS.SUCCESS_RATE} Tasa de éxito: ${this.calculateSuccessRate().toFixed(1)}%`);
		console.log(`${CONSOLE_SYMBOLS.STATUS} Estado final: ${result.status.toUpperCase()}`);
		
		if (this.stats.failed > 0) {
			this.logFailedTestsDetails();
		}

		console.log(`\n${CONSOLE_SYMBOLS.SPARKLES} Ejecución completada ${CONSOLE_SYMBOLS.SPARKLES}\n`);
	}

	/**
	 * Muestra los detalles de todos los tests que fallaron
	 */
	private logFailedTestsDetails(): void {
		console.log(`\n=== ${CONSOLE_SYMBOLS.ERROR} DETALLE DE FALLOS ===`);
		
		this.failedTests.forEach((test, index) => {
			console.log(`\n${index + 1}. Test: ${test.title}`);
			console.log(`   ${CONSOLE_SYMBOLS.LOCATION} Ubicación: ${test.location}`);
			console.log(`   ${CONSOLE_SYMBOLS.TIME} Duración: ${test.duration?.toFixed(2)}s`);
			
			if (test.error) {
				console.error(`   ${CONSOLE_SYMBOLS.DETAIL} Error: ${test.error}`);
			}
		});
	}
}

export default customReporter;