import { AutoReporter } from '../reporters/AutoReporter.js';
/**
 * TESTS PARAMÈTRES EDGE CASES - API Controller
 * Tests des limites de paramètres et pagination
 */

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 Parameters Edge Cases', () => {
  let server;
  let baseUrl;
  const testPort = 3096;

  before(async () => {
    server = new ManualServer({ port: testPort, wsPort: 8096 });
    await server.start();
    baseUrl = `http://localhost:${testPort}`;
    console.log(`📊 Serveur paramètres démarré sur ${baseUrl}`);
  });

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

  describe('📄 Pagination Edge Cases', () => {
    it('should handle extreme pagination values', async () => {
      const testCases = [
        { limit: -1, offset: 0, expected: 'normalize negative limit' },
        { limit: 999999, offset: 0, expected: 'cap very large limit' },
        { limit: 50, offset: -1, expected: 'normalize negative offset' },
        { limit: 0, offset: 0, expected: 'handle zero limit' },
        { limit: 50, offset: 999999, expected: 'handle large offset' }
      ];

      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 normaliser ou échouer gracieusement
        assert.ok([200, 400, 500].includes(response.statusCode),
          `Test case: ${testCase.expected}`);

        if (response.statusCode === 200) {
          assert.ok(response.data.data.limit >= 0, 'Limit should be normalized to >= 0');
          assert.ok(response.data.data.offset >= 0, 'Offset should be normalized to >= 0');
        }
      }
    });

    it('should handle invalid pagination types', async () => {
      const invalidTypes = [
        { limit: 'abc', offset: 0 },
        { limit: 50, offset: 'def' },
        { limit: 'null', offset: 'undefined' },
        { limit: '[]', offset: '{}' },
        { limit: 'true', offset: 'false' }
      ];

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

        // L'API peut convertir ou échouer
        assert.ok([200, 400].includes(response.statusCode));

        if (response.statusCode === 200) {
          // Vérifier que les valeurs sont normalisées
          assert.ok(typeof response.data.data.limit === 'number');
          assert.ok(typeof response.data.data.offset === 'number');
        }
      }
    });

    it('should handle query parameters with special characters', async () => {
      const specialParams = [
        'project=%3Cscript%3E', // <script> encodé
        'status=%22admin%22%20OR%201%3D1', // "admin" OR 1=1 encodé
        'filter=%27%3B%20DROP%20TABLE%3B%20--', // '; DROP TABLE; -- encodé
        'search=%E2%9C%93%F0%9F%92%A9', // Unicode émojis
      ];

      for (const param of specialParams) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: `/api/articles?${param}`,
          method: 'GET'
        });

        // L'API doit gérer les paramètres décodés sans problème
        assert.ok([200, 400, 500].includes(response.statusCode));
      }
    });
  });

  describe('🔢 Limites de Taille', () => {
    it('should handle very long strings in fields', async () => {
      const lengths = [1000, 10000, 100000]; // 1KB, 10KB, 100KB

      for (const length of lengths) {
        const longString = 'A'.repeat(length);

        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: `Test ${length}`,
          description: longString,
          config: { note: `String de ${length} caractères` }
        });

        assert.ok([201, 400, 413].includes(response.statusCode),
          `Failed for ${length} chars`);

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

    it('should handle deeply nested objects', async () => {
      // Objet avec 10 niveaux de profondeur
      let deepObject = { value: 'deep' };
      for (let i = 0; i < 10; i++) {
        deepObject = { level: i, nested: deepObject };
      }

      const response = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, {
        name: 'Deep Object Test',
        description: 'Test objet profond',
        config: deepObject
      });

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

      if (response.statusCode === 201) {
        // Vérifier que la structure est préservée
        assert.ok(response.data.data.config.nested);
      }
    });

    it('should handle arrays with many elements', async () => {
      // Array avec 1000 éléments
      const largeArray = Array(1000).fill().map((_, i) => `item_${i}`);

      const response = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/templates',
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, {
        name: 'Large Array Test',
        content: '<template></template>',
        description: 'Test array volumineux',
        metadata: {
          tags: largeArray,
          count: largeArray.length
        }
      });

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

      if (response.statusCode === 201) {
        assert.strictEqual(response.data.data.metadata.tags.length, 1000);
      }
    });
  });

  describe('🎯 Types de Données Extrêmes', () => {
    it('should handle all JSON primitive types', async () => {
      const primitiveTests = [
        { name: null, type: 'null' },
        { name: undefined, type: 'undefined' },
        { name: true, type: 'boolean true' },
        { name: false, type: 'boolean false' },
        { name: 0, type: 'zero number' },
        { name: -1, type: 'negative number' },
        { name: 1.5, type: 'float number' },
        { name: Number.MAX_SAFE_INTEGER, type: 'max safe integer' },
        { name: '', type: 'empty string' }
      ];

      for (const test of primitiveTests) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: test.name,
          description: `Test type: ${test.type}`
        });

        // L'API peut convertir ou valider
        assert.ok([201, 400].includes(response.statusCode),
          `Failed for type: ${test.type}`);

        if (response.statusCode === 201) {
          // Si accepté, vérifier conversion string
          assert.strictEqual(typeof response.data.data.name, 'string');
        }
      }
    });

    it('should handle Unicode and special characters', async () => {
      const unicodeTests = [
        { name: '🚀 Émojis 中文 русский', desc: 'Unicode mixing' },
        { name: 'Ñoño café naïve', desc: 'Accented characters' },
        { name: '\\n\\t\\r\\0', desc: 'Escape sequences' },
        { name: '\u0001\u0002\u0003', desc: 'Control characters' },
        { name: '𝕳𝖊𝖑𝖑𝖔', desc: 'Mathematical symbols' },
        { name: '♠♥♦♣', desc: 'Special symbols' }
      ];

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

        assert.ok([201, 400].includes(response.statusCode),
          `Failed for: ${test.desc}`);

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

    it('should handle binary and encoded data', async () => {
      // Test avec données binaires encodées
      const binaryData = Buffer.from('Hello World').toString('base64');
      const hexData = Buffer.from('Test Data').toString('hex');

      const tests = [
        { content: binaryData, encoding: 'base64' },
        { content: hexData, encoding: 'hex' },
        { content: encodeURIComponent('Test with spaces & symbols'), encoding: 'urlencoded' }
      ];

      for (const test of tests) {
        const response = await makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/templates',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: `Binary Test ${test.encoding}`,
          content: test.content,
          description: `Test encoding ${test.encoding}`
        });

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

        if (response.statusCode === 201) {
          assert.strictEqual(response.data.data.content, test.content);
        }
      }
    });
  });

  describe('⚡ Performance et Charge', () => {
    it('should handle rapid sequential requests', async () => {
      const startTime = Date.now();
      const results = [];

      // 50 requêtes séquentielles
      for (let i = 0; i < 50; i++) {
        try {
          const response = await makeRequest({
            hostname: 'localhost',
            port: testPort,
            path: '/api/health',
            method: 'GET'
          });
          results.push(response.statusCode);
        } catch (error) {
          results.push('ERROR');
        }
      }

      const duration = Date.now() - startTime;
      const successCount = results.filter(code => code === 200).length;

      console.log(`🏃 Sequential: ${successCount}/50 in ${duration}ms`);

      // Au moins 90% de succès
      assert.ok(successCount >= 45, `Too many failures: ${successCount}/50`);

      // Performance raisonnable (< 10s pour 50 requêtes)
      assert.ok(duration < 10000, `Too slow: ${duration}ms`);
    });

    it('should maintain response consistency under load', async () => {
      // Créer plusieurs projets en parallèle puis vérifier cohérence
      const createPromises = Array(10).fill().map((_, i) =>
        makeRequest({
          hostname: 'localhost',
          port: testPort,
          path: '/api/projects',
          method: 'POST',
          headers: { 'Content-Type': 'application/json' }
        }, {
          name: `Load Test Project ${i}`,
          description: `Project ${i} for load testing`
        })
      );

      const createResults = await Promise.allSettled(createPromises);

      // Vérifier que tous les projets créés ont des IDs uniques
      const successfulCreations = createResults
        .filter(r => r.status === 'fulfilled' && r.value.statusCode === 201)
        .map(r => r.value.data.data);

      const ids = successfulCreations.map(p => p.id);
      const uniqueIds = new Set(ids);

      assert.strictEqual(ids.length, uniqueIds.size, 'All IDs should be unique');
      assert.ok(successfulCreations.length >= 8, 'Most projects should be created successfully');

      // Vérifier que la liste des projets est cohérente
      const listResponse = await makeRequest({
        hostname: 'localhost',
        port: testPort,
        path: '/api/projects',
        method: 'GET'
      });

      assert.strictEqual(listResponse.statusCode, 200);
      assert.ok(listResponse.data.data.projects.length >= successfulCreations.length);
    });

    it('should handle mixed operation types concurrently', async () => {
      // Mix de différentes opérations en parallèle
      const operations = [
        // Health checks
        ...Array(5).fill().map(() => ({ type: 'health', path: '/api/health', method: 'GET' })),

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

        // Project listings
        ...Array(3).fill().map(() => ({ type: 'list', path: '/api/projects', method: 'GET' })),

        // Project creation
        ...Array(5).fill().map((_, i) => ({
          type: 'create',
          path: '/api/projects',
          method: 'POST',
          data: { name: `Mixed Op Project ${i}`, description: 'Mixed operations test' }
        }))
      ];

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

      const results = await Promise.allSettled(promises);

      // Analyser les résultats par type
      const resultsByType = {};
      results.forEach((result, index) => {
        const type = operations[index].type;
        if (!resultsByType[type]) resultsByType[type] = { success: 0, total: 0 };
        resultsByType[type].total++;
        if (result.status === 'fulfilled' && [200, 201].includes(result.value.statusCode)) {
          resultsByType[type].success++;
        }
      });

      // Vérifier que chaque type d'opération a un bon taux de succès
      Object.entries(resultsByType).forEach(([type, stats]) => {
        const successRate = (stats.success / stats.total) * 100;
        console.log(`📊 ${type}: ${successRate.toFixed(1)}% success (${stats.success}/${stats.total})`);
        assert.ok(successRate >= 80, `${type} success rate too low: ${successRate}%`);
      });
    });
  });
});

console.log('📊 Tests Paramètres Edge Cases - Validation limites et performance');