/**
 * Error Handling Integration Tests
 * Exercises invalid inputs and failure paths to confirm the backend responds
 * safely without crashing or corrupting state.
 */
const request = require('supertest');
const app = require('../../../server');

describe('Error Handling and Edge Cases', () => {
    describe('Invalid Query Parameters', () => {
        it('should handle invalid annotated filter value', async () => {
            const res = await request(app).get('/api/models?annotated=maybe');
            expect(res.status).toBe(200);
            // Should return all or handle gracefully
        });

        it('should handle non-boolean query parameters', async () => {
            const res = await request(app).get('/api/models?annotated=123');
            expect(res.status).toBe(200);
            // Should handle gracefully
        });

        it('should handle multiple identical parameters', async () => {
            const res = await request(app).get('/api/models?annotated=true&annotated=false');
            expect(res.status).toBe(200);
        });

        it('should handle empty query parameters', async () => {
            const res = await request(app).get('/api/models?annotated=');
            expect(res.status).toBe(200);
        });
    });

    describe('Malformed Requests', () => {
        it('should handle empty POST body', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({});
            expect(res.status).toBeGreaterThanOrEqual(400);
        });

        it('should handle non-JSON content type', async () => {
            const res = await request(app)
                .post('/annotations')
                .set('Content-Type', 'text/plain')
                .send('invalid data');
            // Should fail validation
            expect(res.status).toBeGreaterThanOrEqual(400);
        });

        it('should handle very long query strings', async () => {
            const longParam = 'a'.repeat(10000);
            const res = await request(app).get(`/api/models?search=${longParam}`);
            // Should handle without crashing
            expect([200, 400]).toContain(res.status);
        });

        it('should handle null values in request body', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: null,
                    annotatorName: null,
                    values: null
                });
            expect(res.status).toBeGreaterThanOrEqual(400);
        });

        it('should handle undefined values in request body', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: undefined,
                    annotatorName: undefined
                });
            expect(res.status).toBeGreaterThanOrEqual(400);
        });
    });

    describe('Boundary Value Testing', () => {
        it('should handle very long string values', async () => {
            const longString = 'x'.repeat(50000);
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: longString,
                    fileHash: 'abc123',
                    values: {}
                });
            // Should handle gracefully
            expect([400, 413, 500]).toContain(res.status);
        });

        it('should handle large nested objects', async () => {
            const largeObject = {};
            for (let i = 0; i < 1000; i++) {
                largeObject[`key${i}`] = `value${i}`;
            }
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: 'test',
                    fileHash: 'abc123',
                    values: largeObject
                });
            // Should handle gracefully
            expect([400, 413, 500]).toContain(res.status);
        });

        it('should handle many array elements', async () => {
            const largeArray = Array.from({ length: 10000 }, (_, i) => i);
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: 'test',
                    fileHash: 'abc123',
                    values: { points: largeArray }
                });
            expect([400, 413, 500]).toContain(res.status);
        });

        it('should handle UUID edge cases', async () => {
            const invalidUUIDs = [
                'not-a-uuid',
                '00000000-0000-0000-0000-000000000000',
                '550e8400-e29b-41d4-a716',
                '550e8400e29b41d4a716446655440000',
                ''
            ];

            for (const uuid of invalidUUIDs) {
                const res = await request(app).get(`/annotations/${uuid}`);
                // Should handle gracefully
                expect([200, 400, 404, 500]).toContain(res.status);
            }
        });
    });

    describe('Special Characters and Encoding', () => {
        it('should handle unicode characters in payload', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: '测试用户🎉',
                    fileHash: 'abc123',
                    values: {}
                });
            expect([200, 400, 500]).toContain(res.status);
        });

        it('should handle special SQL characters', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: "'; DROP TABLE annotations; --",
                    fileHash: 'abc123',
                    values: {}
                });
            expect([200, 400, 500]).toContain(res.status);
            // Data should not be deleted
        });

        it('should handle control characters', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: '550e8400-e29b-41d4-a716-446655440000',
                    annotatorName: 'test\x00\x01\x02user',
                    fileHash: 'abc123',
                    values: {}
                });
            expect([200, 400, 500]).toContain(res.status);
        });

        it('should handle URL-encoded special characters', async () => {
            const res = await request(app)
                .get('/api/models?annotated=%25%20%40%23');
            expect([200, 400]).toContain(res.status);
        });
    });

    describe('Missing Headers', () => {
        it('should work without Content-Type header', async () => {
            const res = await request(app)
                .post('/annotations')
                .set('Content-Type', '')
                .send({});
            // May fail validation but should process
            expect(res.status).toBeGreaterThanOrEqual(400);
        });

        it('should work without custom headers', async () => {
            const res = await request(app)
                .get('/api/atlases')
                .set('X-Custom-Header', '');
            expect(res.status).toBe(200);
        });

        it('should handle missing Accept header', async () => {
            const res = await request(app)
                .get('/api/atlases')
                .set('Accept', '');
            expect([200, 400]).toContain(res.status);
        });
    });

    describe('Concurrent Request Handling', () => {
        it('should handle multiple simultaneous read requests', async () => {
            const promises = Array.from({ length: 10 }, () =>
                request(app).get('/api/atlases')
            );
            const results = await Promise.all(promises);
            
            results.forEach(res => {
                expect(res.status).toBe(200);
            });
        });

        it('should handle concurrent GET and POST requests', async () => {
            const getPromises = Array.from({ length: 5 }, () =>
                request(app).get('/api/models')
            );
            const postPromises = Array.from({ length: 5 }, () =>
                request(app)
                    .post('/annotations')
                    .send({})
            );

            const results = await Promise.all([...getPromises, ...postPromises]);
            expect(results.length).toBe(10);
        });

        it('should handle rapid sequential requests', async () => {
            for (let i = 0; i < 20; i++) {
                const res = await request(app).get('/api/atlases');
                expect(res.status).toBe(200);
            }
        });
    });

    describe('Type Coercion', () => {
        it('should handle string numbers in numeric context', async () => {
            const res = await request(app)
                .get('/api/models?annotated="true"');
            expect([200, 400]).toContain(res.status);
        });

        it('should handle object instead of string', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: { value: '550e8400-e29b-41d4-a716-446655440000' },
                    annotatorName: { name: 'test' },
                    fileHash: 'abc123',
                    values: {}
                });
            expect(res.status).toBeGreaterThanOrEqual(400);
        });

        it('should handle array instead of string', async () => {
            const res = await request(app)
                .post('/annotations')
                .send({
                    atlasId: ['550e8400-e29b-41d4-a716-446655440000'],
                    annotatorName: ['test'],
                    fileHash: 'abc123',
                    values: {}
                });
            expect(res.status).toBeGreaterThanOrEqual(400);
        });
    });

    describe('State Consistency', () => {
        it('should not corrupt state with invalid requests', async () => {
            // First invalid request
            await request(app)
                .post('/annotations')
                .send({ invalid: true });

            // Test that valid request still works
            const validRes = await request(app).get('/api/atlases');
            expect(validRes.status).toBe(200);
        });

        it('should recover from malformed JSON', async () => {
            // Send invalid data first
            try {
                await request(app)
                    .post('/annotations')
                    .set('Content-Type', 'application/json')
                    .send('not json');
            } catch (e) {
                // Expected to fail
            }

            // System should still work
            const res = await request(app).get('/api/models');
            expect(res.status).toBe(200);
        });
    });
});