import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Helper pour créer un environnement DOM simulé
export function createMockDOM() {
    // Mock global objects pour les tests
    global.window = {
        location: { protocol: 'http:', hostname: 'localhost', port: '8080' },
        addEventListener: () => {},
        dispatchEvent: () => {},
        ContentModules: {},
        GameModules: {},
        fetch: async (url) => {
            // Mock fetch pour les tests
            if (url.includes('sbs-level-7-8-new.json')) {
                return {
                    ok: true,
                    json: async () => ({
                        name: "SBS Level 7-8 (New)",
                        description: "Test content",
                        vocabulary: { "test": "test translation" }
                    })
                };
            }
            throw new Error(`Mock fetch: URL not handled: ${url}`);
        }
    };

    global.document = {
        createElement: (tag) => ({
            src: '',
            onload: null,
            onerror: null,
            addEventListener: () => {}
        }),
        querySelector: () => null,
        head: { appendChild: () => {} }
    };

    global.console = {
        log: () => {},
        warn: () => {},
        error: () => {},
        info: () => {},
        debug: () => {}
    };

    // Mock pour logSh
    global.logSh = (message, level = 'INFO') => {
        // Silent dans les tests sauf si on veut debug
        if (process.env.TEST_VERBOSE) {
            console.log(`[TEST ${level}] ${message}`);
        }
    };
}

// Helper pour nettoyer l'environnement après tests
export function cleanupMockDOM() {
    delete global.window;
    delete global.document;
    delete global.console;
    delete global.logSh;
}

// Helper pour charger un fichier JS en tant que module dans les tests
export async function loadModuleForTest(relativePath) {
    const fullPath = path.resolve(__dirname, '../../', relativePath);

    // Lire le fichier et l'évaluer dans le contexte global
    const code = readFileSync(fullPath, 'utf8');

    // Remplacer les exports/require pour le navigateur
    const browserCode = code
        .replace(/export\s+default\s+/g, 'window.TestModule = ')
        .replace(/export\s+\{([^}]+)\}/g, '')
        .replace(/import\s+.*?from\s+['"].*?['"];?\s*/g, '');

    // Évaluer dans le contexte global
    eval(browserCode);

    return global.window.TestModule;
}

// Helper pour créer des données de test
export function createTestContent() {
    return {
        name: "Test Content",
        description: "Content pour les tests",
        difficulty: "medium",
        vocabulary: {
            "hello": "bonjour",
            "world": "monde",
            "test": "test"
        },
        sentences: [
            {
                english: "Hello world",
                chinese: "你好世界",
                prononciation: "nǐ hǎo shì jiè"
            }
        ]
    };
}

// Helper pour simuler des requêtes réseau
export function createMockFetch(responses = {}) {
    return async (url, options = {}) => {
        if (responses[url]) {
            const response = responses[url];
            return {
                ok: response.ok !== false,
                status: response.status || 200,
                json: async () => response.data,
                text: async () => JSON.stringify(response.data)
            };
        }

        // Réponse par défaut
        return {
            ok: false,
            status: 404,
            json: async () => ({ error: 'Not found in mock' }),
            text: async () => 'Not found in mock'
        };
    };
}

// Helper pour attendre un délai
export function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// Helper pour capturer les logs
export function createLogCapture() {
    const logs = [];
    const originalLogSh = global.logSh;

    global.logSh = (message, level = 'INFO') => {
        logs.push({ message, level, timestamp: Date.now() });
        if (originalLogSh) originalLogSh(message, level);
    };

    return {
        logs,
        restore: () => {
            global.logSh = originalLogSh;
        },
        getLogs: (level) => level ? logs.filter(l => l.level === level) : logs,
        clear: () => logs.length = 0
    };
}

// Helper pour les assertions personnalisées
export function assertContains(actual, expected, message) {
    if (!actual.includes(expected)) {
        throw new Error(message || `Expected "${actual}" to contain "${expected}"`);
    }
}

export function assertInstanceOf(actual, expectedClass, message) {
    if (!(actual instanceof expectedClass)) {
        throw new Error(message || `Expected instance of ${expectedClass.name}, got ${actual.constructor.name}`);
    }
}

// Helper pour mocquer les timers
export function createTimerMock() {
    const timers = new Map();
    let timerId = 1;

    const originalSetTimeout = global.setTimeout;
    const originalClearTimeout = global.clearTimeout;

    global.setTimeout = (callback, delay) => {
        const id = timerId++;
        timers.set(id, { callback, delay, type: 'timeout' });
        return id;
    };

    global.clearTimeout = (id) => {
        timers.delete(id);
    };

    return {
        tick: (ms) => {
            for (const [id, timer] of timers.entries()) {
                if (timer.delay <= ms) {
                    timer.callback();
                    timers.delete(id);
                }
            }
        },
        restore: () => {
            global.setTimeout = originalSetTimeout;
            global.clearTimeout = originalClearTimeout;
            timers.clear();
        }
    };
}