import { AutoReporter } from '../reporters/AutoReporter.js';
/**
 * TESTS EDGE CASES - API Controller
 * Tests des cas limites, erreurs et comportements extrêmes
 */

const { describe, it, before, after } = require('node:test');
const assert = require('node:assert');
const http = require('node:http');
const { ManualServer } = require('../../lib/modes/ManualServer');

// Helper pour requêtes HTTP
function makeRequest(options, postData = null) {
  return new Promise((resolve, reject) => {
    const req = http.request(options, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try {
          const parsed = res.headers['content-type']?.includes('application/json')
            ? JSON.parse(data)
            : data;
          resolve({ statusCode: res.statusCode, headers: res.headers, data: parsed });
        } catch (e) {
          resolve({ statusCode: res.statusCode, headers: res.headers, data });
        }
      });
    });

    req.on('error', reject);
    req.setTimeout(10000, () => {
      req.destroy();
      reject(new Error('Request timeout'));
    });

    if (postData) {
      req.write(typeof postData === 'object' ? JSON.stringify(postData) : postData);
    }
    req.end();
  });
}


// Auto-Reporter Configuration
const autoReporter = new AutoReporter();

describe('API Edge Cases - Tests des Cas Limites', () => {
  let server;
  let baseUrl;
  const testPort = 3098; // Port différent pour éviter conflits

  before(async () => {
    server = new ManualServer({ port: testPort, wsPort: 8098 });
    await server.start();
    baseUrl = `http://localhost:${testPort}`;
    console.log(`🧪 Serveur edge cases démarré sur ${baseUrl}`);
  });

  after(async () => {
    if (server) {
      await server.stop();
      console.log('🛑 Serveur edge cases arrêté');
    }
  });

  describe('🔥 Paramètres Extrêmes', () => {
    it('should handle very long project names', async () => {
      const longName = 'A'.repeat(10000); // 10KB de nom

      const response = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, {
        name: longName,
        description: 'Test nom très long'
      });

      // L'API doit gérer les noms longs gracieusement
      assert.ok([201, 400].includes(response.statusCode));

      if (response.statusCode === 201) {
        assert.strictEqual(response.data.success, true);
        assert.strictEqual(response.data.data.name, longName);
      } else {
        assert.strictEqual(response.data.success, false);
      }
    });

    it('should handle pagination with extreme values', async () => {
      // Test avec des valeurs de pagination extrêmes
      const testCases = [
        { limit: -1, offset: 0 },
        { limit: 999999, offset: 0 },
        { limit: 50, offset: -1 },
        { limit: 'invalid', offset: 'invalid' },
        { limit: 0, offset: 999999 }
      ];

      for (const testCase of testCases) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: `/api/articles?limit=${testCase.limit}&offset=${testCase.offset}`,
          method: 'GET'
        });

        // L'API doit soit réussir avec des valeurs normalisées, soit échouer gracieusement
        assert.ok([200, 400, 500].includes(response.statusCode));

        if (response.statusCode === 200) {
          assert.ok(response.data.data.limit >= 0);
          assert.ok(response.data.data.offset >= 0);
        }
      }
    });

    it('should handle special characters in all fields', async () => {
      const specialChars = {
        name: '🚀 Test "Special" <script>alert(1)</script> & émojis 中文',
        description: 'Description avec \n\t\r caractères spéciaux \\n "quotes" \'single\' & symbols €£¥',
        config: {
          special: '<>&"\'{}[]()=+-*/\\',
          unicode: '🎯🔥💯✨🌟⭐',
          mixed: 'Normal text avec 中文 и русский'
        }
      };

      const response = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, specialChars);

      assert.ok([201, 400].includes(response.statusCode));

      if (response.statusCode === 201) {
        assert.strictEqual(response.data.data.name, specialChars.name);
        assert.strictEqual(response.data.data.description, specialChars.description);
      }
    });
  });

  describe('🛡️ Sécurité et Injection', () => {
    it('should reject SQL injection attempts', async () => {
      const sqlInjections = [
        "'; DROP TABLE projects; --",
        "1' OR '1'='1",
        "admin'/*",
        "1; SELECT * FROM users; --"
      ];

      for (const injection of sqlInjections) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: injection,
          description: 'Test injection SQL'
        });

        // L'API doit traiter cela comme une chaîne normale, pas d'injection
        assert.ok([201, 400].includes(response.statusCode));

        if (response.statusCode === 201) {
          assert.strictEqual(response.data.data.name, injection); // Stocké tel quel
        }
      }
    });

    it('should handle XSS attempts gracefully', async () => {
      const xssPayloads = [
        '<script>alert("XSS")</script>',
        'javascript:alert(1)',
        '<img src=x onerror=alert(1)>',
        '<svg onload=alert(1)>'
      ];

      for (const payload of xssPayloads) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/templates',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: 'Test XSS',
          content: payload,
          description: 'Template avec payload XSS'
        });

        assert.ok([201, 400].includes(response.statusCode));

        if (response.statusCode === 201) {
          // Le payload doit être stocké tel quel (pas d'exécution côté serveur)
          assert.strictEqual(response.data.data.content, payload);
        }
      }
    });

    it('should validate content-type header requirements', async () => {
      // Test sans Content-Type
      const response1 = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST'
      }, '{"name":"Test"}');

      // Test avec mauvais Content-Type
      const response2 = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST',
        headers: { 'Content-Type': 'text/plain' }
      }, '{"name":"Test"}');

      // Express devrait gérer ces cas
      assert.ok([400, 415, 500].includes(response1.statusCode));
      assert.ok([400, 415, 500].includes(response2.statusCode));
    });
  });

  describe('💣 Cas d\'Erreur Extrêmes', () => {
    it('should handle malformed JSON gracefully', async () => {
      const malformedJsons = [
        '{"name":}',
        '{"name":"test",}',
        '{name:"test"}',
        '{"name":"test"',
        'null',
        'undefined',
        '',
        '[]',
        'true'
      ];

      for (const json of malformedJsons) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, json);

        assert.strictEqual(response.statusCode, 400);
        assert.strictEqual(response.data.success, false);
      }
    });

    it('should handle very large payloads', async () => {
      // Payload de 1MB
      const largePayload = {
        name: 'Large Test',
        description: 'X'.repeat(1024 * 1024), // 1MB de description
        config: {
          data: 'Y'.repeat(100000) // 100KB supplémentaires
        }
      };

      const response = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, largePayload);

      // L'API peut soit accepter, soit rejeter selon les limites configurées
      assert.ok([201, 400, 413].includes(response.statusCode));
    });

    it('should handle concurrent requests without corruption', async () => {
      // 20 requêtes simultanées
      const promises = Array(20).fill().map((_, i) =>
        makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: `Concurrent Project ${i}`,
          description: `Test concurrence ${i}`
        })
      );

      const results = await Promise.allSettled(promises);

      // Compter les succès
      const successes = results.filter(r =>
        r.status === 'fulfilled' && r.value.statusCode === 201
      );

      // Au moins quelques requêtes doivent réussir
      assert.ok(successes.length > 0);

      // Vérifier que les IDs sont uniques
      const ids = successes.map(r => r.value.data.data.id);
      const uniqueIds = new Set(ids);
      assert.strictEqual(ids.length, uniqueIds.size, 'IDs doivent être uniques');
    });
  });

  describe('🌐 Protocole HTTP Edge Cases', () => {
    it('should handle unsupported HTTP methods', async () => {
      const methods = ['PATCH', 'DELETE', 'HEAD', 'TRACE', 'CONNECT'];

      for (const method of methods) {
        try {
          const response = await makeRequest({
            hostname: 'localhost',
            port: testPort,
            path: '/api/projects',
            method
          });

          // 405 Method Not Allowed ou 404
          assert.ok([404, 405].includes(response.statusCode));
        } catch (error) {
          // Certaines méthodes peuvent être rejetées par Node.js
          assert.ok(error.message.includes('Method') || error.message.includes('method'));
        }
      }
    });

    it('should handle invalid URLs and paths', async () => {
      const invalidPaths = [
        '/api/projects/../../../etc/passwd',
        '/api/projects/%2e%2e%2f%2e%2e%2f',
        '/api/projects/\\..\\..\\windows\\system32',
        '/api/projects?' + 'x'.repeat(10000), // Query string très longue
        '/api/projects#fragment',
        '/api/projects with spaces',
        '/api/проекты', // URL avec caractères non-ASCII
      ];

      for (const path of invalidPaths) {
        try {
          const response = await makeRequest({
            hostname: 'localhost',
            port: testPort,
            path,
            method: 'GET'
          });

          // Doit retourner 404 ou 400, pas d'erreur de sécurité
          assert.ok([400, 404].includes(response.statusCode));
        } catch (error) {
          // Erreurs de parsing d'URL attendues
          assert.ok(error.message.includes('Invalid') || error.message.includes('URI'));
        }
      }
    });

    it('should handle connection timeouts gracefully', async () => {
      // Test avec un article qui va prendre du temps (workflow LLM)
      const startTime = Date.now();

      try {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/articles',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          keyword: 'test timeout edge case',
          project: 'timeout-test'
        });

        const duration = Date.now() - startTime;

        // Si ça réussit, vérifier que c'est raisonnable
        if (response.statusCode === 201) {
          assert.ok(duration < 120000, `Article generation took ${duration}ms`);
          assert.strictEqual(response.data.success, true);
        } else {
          // Erreur attendue (timeout LLM, etc.)
          assert.strictEqual(response.data.success, false);
        }

      } catch (error) {
        // Timeout de requête attendu
        assert.ok(error.message.includes('timeout') || error.message.includes('Timeout'));
      }
    });
  });

  describe('📊 Performance Edge Cases', () => {
    it('should handle rapid successive requests', async () => {
      const requests = [];
      const startTime = Date.now();

      // 50 requêtes health check rapides
      for (let i = 0; i < 50; i++) {
        requests.push(
          makeRequest({
            hostname: 'localhost',
            port: testPort,
            path: '/api/health',
            method: 'GET'
          })
        );
      }

      const results = await Promise.allSettled(requests);
      const duration = Date.now() - startTime;

      const successes = results.filter(r =>
        r.status === 'fulfilled' && r.value.statusCode === 200
      );

      // La plupart des requêtes doivent réussir
      assert.ok(successes.length >= 45, `Only ${successes.length}/50 requests succeeded`);

      // Performance raisonnable
      assert.ok(duration < 5000, `50 health checks took ${duration}ms`);

      console.log(`📈 Performance: ${successes.length}/50 requests in ${duration}ms`);
    });

    it('should maintain stability under stress', async () => {
      // Mix de différents types de requêtes
      const stressRequests = [
        // Health checks
        ...Array(10).fill().map(() => ({ path: '/api/health', method: 'GET' })),

        // Metrics
        ...Array(5).fill().map(() => ({ path: '/api/metrics', method: 'GET' })),

        // Project creation
        ...Array(5).fill().map((_, i) => ({
          path: '/api/projects',
          method: 'POST',
          data: { name: `Stress Project ${i}`, description: 'Stress test' }
        })),

        // Template creation
        ...Array(3).fill().map((_, i) => ({
          path: '/api/templates',
          method: 'POST',
          data: { name: `Stress Template ${i}`, content: '<template></template>' }
        }))
      ];

      const promises = stressRequests.map(req =>
        makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: req.path,
          method: req.method,
          headers: req.data ? { 'Content-Type': 'application/json' } : {}
        }, req.data)
      );

      const results = await Promise.allSettled(promises);

      // Calculer taux de succès
      const successes = results.filter(r =>
        r.status === 'fulfilled' && [200, 201].includes(r.value.statusCode)
      );

      const successRate = (successes.length / results.length) * 100;
      console.log(`🎯 Stress test: ${successRate.toFixed(1)}% success rate`);

      // Au moins 80% de succès attendu
      assert.ok(successRate >= 80, `Success rate too low: ${successRate}%`);
    });
  });
});

console.log('🧪 Tests Edge Cases API - Validation des cas limites et sécurité');