import { test, describe, beforeEach, afterEach } from 'node:test';
import { strict as assert } from 'node:assert';
import { spawn } from 'child_process';
import { readFileSync } from 'fs';
import path from 'path';

// Test d'intégration pour le proxy DigitalOcean
describe('Proxy DigitalOcean - Tests d\'Intégration', () => {
    let proxyProcess;
    const proxyPort = 8083;
    const proxyUrl = `http://localhost:${proxyPort}`;

    // Helper pour faire des requêtes HTTP
    async function makeRequest(path, options = {}) {
        const fetch = (await import('node-fetch')).default;
        const url = `${proxyUrl}${path}`;

        try {
            const response = await fetch(url, {
                timeout: 5000,
                ...options
            });

            return {
                ok: response.ok,
                status: response.status,
                data: response.ok ? await response.text() : await response.text(),
                headers: Object.fromEntries(response.headers.entries())
            };
        } catch (error) {
            return {
                ok: false,
                error: error.message
            };
        }
    }

    // Helper pour attendre que le serveur soit prêt
    async function waitForServer(maxAttempts = 10, delay = 1000) {
        for (let i = 0; i < maxAttempts; i++) {
            try {
                const response = await makeRequest('/do-proxy/_list');
                if (response.status) {
                    return true;
                }
            } catch (error) {
                // Ignorer les erreurs de connexion
            }
            await new Promise(resolve => setTimeout(resolve, delay));
        }
        return false;
    }

    beforeEach(async () => {
        // Démarrer le serveur proxy si pas déjà actif
        try {
            const testResponse = await makeRequest('/do-proxy/_list');
            if (testResponse.status) {
                console.log('🟢 Serveur proxy déjà actif');
                return;
            }
        } catch (error) {
            // Server not running, start it
        }

        console.log('🚀 Démarrage du serveur proxy pour les tests...');

        const serverPath = path.resolve(process.cwd(), 'export_logger/websocket-server.js');
        proxyProcess = spawn('node', [serverPath], {
            cwd: path.dirname(serverPath),
            stdio: ['pipe', 'pipe', 'pipe'],
            detached: false
        });

        // Attendre que le serveur soit prêt
        const isReady = await waitForServer();
        if (!isReady) {
            throw new Error('Impossible de démarrer le serveur proxy pour les tests');
        }

        console.log('✅ Serveur proxy prêt');
    });

    afterEach(() => {
        // Ne pas arrêter le serveur car il peut être utilisé par d'autres tests
        // ou l'application principale
        if (proxyProcess && !proxyProcess.killed) {
            // proxyProcess.kill();
        }
    });

    describe('Endpoints du proxy', () => {
        test('GET /do-proxy/sbs-level-7-8-new.json devrait retourner du JSON valide', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json');

            assert.equal(response.ok, true, `Request failed: ${response.error || response.data}`);
            assert.equal(response.status, 200);

            // Vérifier que c'est du JSON valide
            let jsonData;
            try {
                jsonData = JSON.parse(response.data);
            } catch (error) {
                assert.fail(`Response is not valid JSON: ${error.message}`);
            }

            // Vérifier la structure du contenu
            assert.ok(jsonData.name, 'JSON should have a name field');
            assert.ok(jsonData.vocabulary, 'JSON should have a vocabulary field');
            assert.equal(typeof jsonData.vocabulary, 'object');
        });

        test('GET /do-proxy/english-class-demo.json devrait retourner du contenu', async () => {
            const response = await makeRequest('/do-proxy/english-class-demo.json');

            assert.equal(response.ok, true, `Request failed: ${response.error || response.data}`);
            assert.equal(response.status, 200);

            let jsonData;
            try {
                jsonData = JSON.parse(response.data);
            } catch (error) {
                assert.fail(`Response is not valid JSON: ${error.message}`);
            }

            assert.ok(jsonData.name || jsonData.vocabulary, 'JSON should have content');
        });

        test('HEAD /do-proxy/sbs-level-7-8-new.json devrait retourner headers sans body', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json', {
                method: 'HEAD'
            });

            assert.equal(response.ok, true);
            assert.equal(response.status, 200);
            // HEAD request should have empty or minimal body
            assert.ok(response.data.length <= 100, 'HEAD response should have minimal content');
        });

        test('GET /do-proxy/nonexistent.json devrait retourner 404', async () => {
            const response = await makeRequest('/do-proxy/nonexistent-file-12345.json');

            assert.equal(response.ok, false);
            // Should be either 404 (not found) or 403 (forbidden)
            assert.ok([403, 404].includes(response.status));
        });
    });

    describe('CORS et headers', () => {
        test('les réponses devrait inclure les headers CORS', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json');

            assert.equal(response.ok, true);
            assert.ok(response.headers['access-control-allow-origin']);
            assert.equal(response.headers['access-control-allow-origin'], '*');
        });

        test('OPTIONS request devrait être supportée', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json', {
                method: 'OPTIONS'
            });

            assert.equal(response.status, 200);
            assert.ok(response.headers['access-control-allow-origin']);
            assert.ok(response.headers['access-control-allow-methods']);
        });
    });

    describe('Listing des fichiers', () => {
        test('GET /do-proxy/_list devrait retourner une liste de fichiers ou une erreur 403', async () => {
            const response = await makeRequest('/do-proxy/_list');

            // Le listing peut échouer avec 403 (permissions insuffisantes) ce qui est attendu
            if (response.status === 403) {
                let jsonData;
                try {
                    jsonData = JSON.parse(response.data);
                } catch (error) {
                    assert.fail('403 response should be valid JSON');
                }

                assert.ok(jsonData.error, 'Should contain error message');
                assert.ok(jsonData.knownFiles, 'Should contain known files list');
                assert.ok(Array.isArray(jsonData.knownFiles));
            } else if (response.status === 200) {
                let jsonData;
                try {
                    jsonData = JSON.parse(response.data);
                } catch (error) {
                    assert.fail('200 response should be valid JSON');
                }

                assert.ok(jsonData.files, 'Should contain files array');
                assert.ok(Array.isArray(jsonData.files));
            } else {
                assert.fail(`Unexpected status: ${response.status}`);
            }
        });
    });

    describe('Performance et timeouts', () => {
        test('les requêtes devrait répondre dans un délai raisonnable', async () => {
            const startTime = Date.now();
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json');
            const endTime = Date.now();

            assert.equal(response.ok, true);

            const responseTime = endTime - startTime;
            assert.ok(responseTime < 10000, `Response time too slow: ${responseTime}ms`);
        });

        test('les requêtes multiples simultanées devrait fonctionner', async () => {
            const promises = [
                makeRequest('/do-proxy/sbs-level-7-8-new.json'),
                makeRequest('/do-proxy/english-class-demo.json'),
                makeRequest('/do-proxy/sbs-level-7-8-new.json') // Duplicate to test caching
            ];

            const responses = await Promise.all(promises);

            responses.forEach((response, index) => {
                assert.equal(response.ok, true, `Request ${index} failed: ${response.error}`);
                assert.equal(response.status, 200);
            });
        });
    });

    describe('Authentification AWS', () => {
        test('les requêtes devrait inclure les headers d\'authentification AWS', async () => {
            // Ce test vérifie indirectement l'authentification en s'attendant à ce que
            // les requêtes réussissent, ce qui nécessite une authentification correcte
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json');

            assert.equal(response.ok, true, 'Authentication should work for valid files');
            assert.equal(response.status, 200);

            // Si l'authentification échoue, on obtiendrait typiquement 403 Forbidden
            // Le fait que nous obtenons 200 indique que l'authentification fonctionne
        });
    });

    describe('Gestion des erreurs', () => {
        test('les routes invalides devrait retourner 404', async () => {
            const response = await makeRequest('/invalid-route');

            assert.equal(response.ok, false);
            assert.equal(response.status, 404);
        });

        test('les méthodes non supportées devrait retourner une erreur', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json', {
                method: 'PUT'
            });

            // PUT n'est pas supporté, devrait retourner une erreur
            assert.equal(response.ok, false);
        });
    });

    describe('Intégration avec DigitalOcean Spaces', () => {
        test('devrait pouvoir récupérer des fichiers réels depuis DigitalOcean', async () => {
            const response = await makeRequest('/do-proxy/sbs-level-7-8-new.json');

            if (response.ok) {
                const jsonData = JSON.parse(response.data);

                // Vérifier que le contenu a la structure attendue d'un fichier de contenu
                assert.ok(jsonData.name || jsonData.vocabulary, 'Should contain educational content');

                if (jsonData.vocabulary) {
                    assert.equal(typeof jsonData.vocabulary, 'object');
                    assert.ok(Object.keys(jsonData.vocabulary).length > 0, 'Vocabulary should not be empty');
                }
            } else {
                // Si la connexion à DigitalOcean échoue, au moins vérifier que l'erreur est appropriée
                assert.ok([403, 404, 500].includes(response.status),
                    `Unexpected error status: ${response.status}`);
            }
        });
    });
});