import { test, describe, beforeEach, afterEach } from 'node:test';
import { strict as assert } from 'node:assert';
import { createMockDOM, cleanupMockDOM, createLogCapture } from '../utils/test-helpers.js';
import { readFileSync } from 'fs';
import path from 'path';

// Test d'intégration pour le système de navigation
describe('Système de Navigation - Tests d\'Intégration', () => {
    let AppNavigation;
    let logCapture;
    let navigationEvents = [];

    beforeEach(() => {
        createMockDOM();
        logCapture = createLogCapture();
        navigationEvents = [];

        // Mock plus complet pour DOM
        global.document = {
            ...global.document,
            getElementById: (id) => {
                const elements = {
                    'app': { style: {}, innerHTML: '', classList: { add: () => {}, remove: () => {} } },
                    'home-page': { style: {}, innerHTML: '', classList: { add: () => {}, remove: () => {} } },
                    'games-page': { style: {}, innerHTML: '', classList: { add: () => {}, remove: () => {} } },
                    'levels-page': { style: {}, innerHTML: '', classList: { add: () => {}, remove: () => {} } },
                    'game-page': { style: {}, innerHTML: '', classList: { add: () => {}, remove: () => {} } },
                    'breadcrumb': { innerHTML: '', style: {} },
                    'network-status': { textContent: '', className: '', style: {} }
                };
                return elements[id] || null;
            },
            querySelectorAll: () => [],
            addEventListener: (event, handler) => {
                global.document[`_${event}_handler`] = handler;
            }
        };

        // Mock window avec navigation
        global.window = {
            ...global.window,
            location: {
                protocol: 'http:',
                hostname: 'localhost',
                port: '8080',
                search: '',
                href: 'http://localhost:8080/',
                assign: (url) => {
                    global.window.location.href = url;
                    global.window.location.search = url.includes('?') ? url.split('?')[1] : '';
                    navigationEvents.push({ type: 'assign', url });
                }
            },
            history: {
                pushState: (state, title, url) => {
                    global.window.location.href = url;
                    global.window.location.search = url.includes('?') ? url.split('?')[1] : '';
                    navigationEvents.push({ type: 'pushState', state, title, url });
                },
                replaceState: (state, title, url) => {
                    global.window.location.href = url;
                    global.window.location.search = url.includes('?') ? url.split('?')[1] : '';
                    navigationEvents.push({ type: 'replaceState', state, title, url });
                }
            },
            addEventListener: (event, handler) => {
                global.window[`_${event}_handler`] = handler;
            },
            dispatchEvent: (event) => {
                if (event.type === 'popstate' && global.window._popstate_handler) {
                    global.window._popstate_handler(event);
                }
            }
        };

        // Mock URLSearchParams
        global.URLSearchParams = class {
            constructor(search) {
                this.params = new Map();
                if (search) {
                    search.split('&').forEach(param => {
                        const [key, value] = param.split('=');
                        if (key && value) {
                            this.params.set(decodeURIComponent(key), decodeURIComponent(value));
                        }
                    });
                }
            }

            get(key) {
                return this.params.get(key);
            }

            set(key, value) {
                this.params.set(key, value);
            }

            toString() {
                const pairs = [];
                for (const [key, value] of this.params) {
                    pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
                }
                return pairs.join('&');
            }
        };

        // Charger AppNavigation
        const navPath = path.resolve(process.cwd(), 'js/core/navigation.js');
        const code = readFileSync(navPath, 'utf8');

        const testCode = code
            .replace(/window\./g, 'global.')
            .replace(/typeof window !== 'undefined'/g, 'true');

        eval(testCode);
        AppNavigation = global.AppNavigation;
    });

    afterEach(() => {
        logCapture.restore();
        cleanupMockDOM();
    });

    describe('Initialisation et configuration', () => {
        test('devrait créer une instance AppNavigation', () => {
            const nav = new AppNavigation();

            assert.ok(nav instanceof AppNavigation);
            assert.ok(Array.isArray(nav.navigationHistory));
            assert.equal(nav.navigationHistory.length, 0);
        });

        test('devrait charger la configuration par défaut', () => {
            const nav = new AppNavigation();
            const config = nav.getDefaultConfig();

            assert.ok(config);
            assert.ok(config.games);
            assert.ok(config.content);
            assert.ok(config.ui);
        });
    });

    describe('Analyse d\'URL et paramètres', () => {
        test('parseURLParams devrait extraire les paramètres correctement', () => {
            const nav = new AppNavigation();

            global.window.location.search = '?page=games&game=whack&content=sbs8';
            const params = nav.parseURLParams();

            assert.equal(params.page, 'games');
            assert.equal(params.game, 'whack');
            assert.equal(params.content, 'sbs8');
        });

        test('parseURLParams devrait retourner objet vide si pas de paramètres', () => {
            const nav = new AppNavigation();

            global.window.location.search = '';
            const params = nav.parseURLParams();

            assert.equal(Object.keys(params).length, 0);
        });

        test('getCurrentRoute devrait identifier la route actuelle', () => {
            const nav = new AppNavigation();

            // Test route home
            global.window.location.search = '';
            assert.equal(nav.getCurrentRoute(), 'home');

            // Test route games
            global.window.location.search = '?page=games';
            assert.equal(nav.getCurrentRoute(), 'games');

            // Test route play
            global.window.location.search = '?page=play&game=whack&content=sbs8';
            assert.equal(nav.getCurrentRoute(), 'play');
        });
    });

    describe('Navigation et routage', () => {
        test('navigateTo devrait mettre à jour l\'URL et l\'historique', () => {
            const nav = new AppNavigation();

            nav.navigateTo('games', { category: 'vocabulary' });

            assert.equal(navigationEvents.length, 1);
            assert.equal(navigationEvents[0].type, 'pushState');
            assert.ok(navigationEvents[0].url.includes('page=games'));
            assert.ok(navigationEvents[0].url.includes('category=vocabulary'));

            assert.equal(nav.navigationHistory.length, 1);
            assert.equal(nav.navigationHistory[0].page, 'games');
        });

        test('navigateToGame devrait créer l\'URL correcte pour un jeu', () => {
            const nav = new AppNavigation();

            nav.navigateToGame('whack-a-mole', 'sbs-content');

            const lastEvent = navigationEvents[navigationEvents.length - 1];
            assert.ok(lastEvent.url.includes('page=play'));
            assert.ok(lastEvent.url.includes('game=whack-a-mole'));
            assert.ok(lastEvent.url.includes('content=sbs-content'));
        });

        test('goBack devrait revenir à la page précédente', () => {
            const nav = new AppNavigation();

            // Naviguer vers quelques pages
            nav.navigateTo('games');
            nav.navigateTo('levels', { game: 'whack' });
            nav.navigateTo('play', { game: 'whack', content: 'sbs8' });

            assert.equal(nav.navigationHistory.length, 3);

            // Revenir en arrière
            nav.goBack();

            assert.equal(nav.navigationHistory.length, 2);
            const lastEvent = navigationEvents[navigationEvents.length - 1];
            assert.ok(lastEvent.url.includes('page=levels'));
        });

        test('handlePopState devrait gérer les événements navigateur', () => {
            const nav = new AppNavigation();

            // Simuler un événement popstate
            const mockEvent = {
                state: { page: 'games', timestamp: Date.now() }
            };

            nav.handlePopState(mockEvent);

            // Devrait déclencher une mise à jour de la page
            const logs = logCapture.getLogs();
            assert.ok(logs.some(log => log.message.includes('Navigation')));
        });
    });

    describe('Gestion des pages', () => {
        test('showPage devrait afficher la page correcte', () => {
            const nav = new AppNavigation();

            nav.showPage('games');

            // Vérifier que les éléments DOM sont mis à jour
            const gamesPage = global.document.getElementById('games-page');
            const homePage = global.document.getElementById('home-page');

            // Les styles devraient être mis à jour pour afficher/masquer les pages
            assert.ok(gamesPage); // Should exist
            assert.ok(homePage); // Should exist
        });

        test('updateBreadcrumb devrait mettre à jour le fil d\'Ariane', () => {
            const nav = new AppNavigation();

            nav.updateBreadcrumb(['Accueil', 'Jeux', 'Whack-a-Mole']);

            const breadcrumb = global.document.getElementById('breadcrumb');
            assert.ok(breadcrumb.innerHTML.length > 0);
        });
    });

    describe('État de connectivité', () => {
        test('updateNetworkStatus devrait mettre à jour l\'indicateur réseau', () => {
            const nav = new AppNavigation();

            nav.updateNetworkStatus('online');

            const networkStatus = global.document.getElementById('network-status');
            assert.ok(networkStatus.className.includes('online') || networkStatus.textContent.includes('online'));
        });

        test('devrait gérer différents états de réseau', () => {
            const nav = new AppNavigation();

            const states = ['online', 'offline', 'connecting'];

            states.forEach(state => {
                nav.updateNetworkStatus(state);
                const networkStatus = global.document.getElementById('network-status');
                assert.ok(networkStatus.className.includes(state) || networkStatus.textContent);
            });
        });
    });

    describe('Validation de routes', () => {
        test('isValidRoute devrait valider les routes connues', () => {
            const nav = new AppNavigation();

            assert.equal(nav.isValidRoute('home'), true);
            assert.equal(nav.isValidRoute('games'), true);
            assert.equal(nav.isValidRoute('levels'), true);
            assert.equal(nav.isValidRoute('play'), true);
            assert.equal(nav.isValidRoute('invalid-route'), false);
        });

        test('validateParams devrait valider les paramètres requis', () => {
            const nav = new AppNavigation();

            // Route play nécessite game et content
            const validParams = { page: 'play', game: 'whack', content: 'sbs8' };
            const invalidParams1 = { page: 'play', game: 'whack' }; // manque content
            const invalidParams2 = { page: 'play', content: 'sbs8' }; // manque game

            assert.equal(nav.validateParams(validParams), true);
            assert.equal(nav.validateParams(invalidParams1), false);
            assert.equal(nav.validateParams(invalidParams2), false);
        });
    });

    describe('Intégration avec le système de jeu', () => {
        test('devrait intégrer avec GameLoader pour charger les jeux', () => {
            const nav = new AppNavigation();

            // Mock GameLoader
            global.GameLoader = class {
                async loadGame(gameType, contentType, container) {
                    return {
                        gameType,
                        contentType,
                        started: false,
                        start: function() { this.started = true; }
                    };
                }
            };

            // Simuler une navigation vers un jeu
            global.window.location.search = '?page=play&game=whack&content=sbs8';

            // L'initialisation devrait déclencher le chargement du jeu
            nav.init();

            const logs = logCapture.getLogs();
            assert.ok(logs.some(log => log.message.includes('Navigation') || log.message.includes('Initialisation')));
        });
    });

    describe('Gestion des erreurs de navigation', () => {
        test('devrait gérer les URLs invalides gracieusement', () => {
            const nav = new AppNavigation();

            global.window.location.search = '?page=invalid&param=malformed%';

            try {
                nav.init();
                // Ne devrait pas lever d'erreur
                assert.ok(true);
            } catch (error) {
                assert.fail(`Navigation should handle invalid URLs gracefully: ${error.message}`);
            }
        });

        test('devrait rediriger vers home si route invalide', () => {
            const nav = new AppNavigation();

            nav.navigateTo('invalid-page');

            // Devrait rediriger vers home
            const lastEvent = navigationEvents[navigationEvents.length - 1];
            assert.ok(lastEvent.url.includes('page=home') || !lastEvent.url.includes('page='));
        });
    });

    describe('Historique de navigation', () => {
        test('devrait maintenir un historique de navigation', () => {
            const nav = new AppNavigation();

            nav.navigateTo('games');
            nav.navigateTo('levels', { game: 'whack' });
            nav.navigateTo('play', { game: 'whack', content: 'sbs8' });

            assert.equal(nav.navigationHistory.length, 3);

            const history = nav.getNavigationHistory();
            assert.equal(history.length, 3);
            assert.equal(history[0].page, 'games');
            assert.equal(history[1].page, 'levels');
            assert.equal(history[2].page, 'play');
        });

        test('devrait limiter la taille de l\'historique', () => {
            const nav = new AppNavigation();

            // Naviguer vers de nombreuses pages
            for (let i = 0; i < 25; i++) {
                nav.navigateTo('games', { test: i });
            }

            // L'historique devrait être limité
            assert.ok(nav.navigationHistory.length <= 20);
        });
    });

    describe('Événements personnalisés', () => {
        test('devrait émettre des événements de navigation', () => {
            const nav = new AppNavigation();

            let eventReceived = false;
            global.window.addEventListener = (event, handler) => {
                if (event === 'navigationChange') {
                    eventReceived = true;
                }
            };

            nav.navigateTo('games');

            // L'événement devrait être émis (ou préparé pour émission)
            assert.ok(navigationEvents.length > 0);
        });
    });
});