/// <reference types="jest" />
import { DataProcessor, AggregateResult } from '../src/core/dataProcessor';

describe('DataProcessor Algorithm & Performance Validation', () => {
    
    // 1. 정합성 테스트 (Correctness)
    test('Should correctly aggregate data by key path', () => {
        const testData = [
            { category: 'A', value: 10 },
            { category: 'B', value: 20 },
            { category: 'A', value: 30 },
            { category: 'C', value: 40 },
        ];

        const result = DataProcessor.aggregate(testData, 'category');

        expect(result.length).toBe(3);
        expect(result.find((r: AggregateResult) => r.key === 'A')?.count).toBe(2);
        expect(result.find((r: AggregateResult) => r.key === 'B')?.count).toBe(1);
    });

    // 2. 예외 처리 테스트 (Robustness)
    test('Should handle invalid or missing key paths gracefully', () => {
        const testData = [
            { id: 1, info: { type: 'X' } },
            { id: 2 }, // info.type 없음
            { id: 3, info: null }, // info.type 접근 불가
        ];

        const result = DataProcessor.aggregate(testData, 'info.type');

        expect(result.length).toBe(1);
        expect(result[0].key).toBe('X');
    });

    test('Should reject unsafe or malformed key paths', () => {
        expect(() => DataProcessor.aggregate([{ a: 1 }], '')).toThrow(TypeError);
        expect(() => DataProcessor.aggregate([{ a: 1 }], 'a..b')).toThrow(TypeError);
        expect(() => DataProcessor.aggregate([{ a: 1 }], '__proto__.polluted')).toThrow(TypeError);
    });

    test('Should support aggregation without retaining source values', () => {
        const result = DataProcessor.aggregate([
            { category: 'A', value: 10 },
            { category: 'A', value: 20 },
        ], 'category', { collectValues: false });

        expect(result).toHaveLength(1);
        expect(result[0].count).toBe(2);
        expect(result[0].values).toEqual([]);
    });

    // 3. 성능 벤치마크 (O(N) vs O(N^2) 검증)
    test('O(N) Efficiency Benchmark', () => {
        const generateData = (n: number) => {
            return Array.from({ length: n }, (_, i) => ({
                id: i,
                group: `group_${i % 100}`
            }));
        };

        const smallN = 1000;
        const largeN = 100000; // 100배 증가

        // Small dataset test
        const smallData = generateData(smallN);
        const startSmall = performance.now();
        DataProcessor.aggregate(smallData, 'group');
        const endSmall = performance.now();
        const durationSmall = endSmall - startSmall;

        // Large dataset test
        const largeData = generateData(largeN);
        const startLarge = performance.now();
        DataProcessor.aggregate(largeData, 'group');
        const endLarge = performance.now();
        const durationLarge = endLarge - startLarge;

        console.log(`[Benchmark] N=${smallN}: ${durationSmall.toFixed(4)}ms`);
        console.log(`[Benchmark] N=${largeN}: ${durationLarge.toFixed(4)}ms`);
        console.log(`[Benchmark] Scale Factor (N x 100): ${(durationLarge / durationSmall).toFixed(2)}x time`);

        // O(N^2)이었다면 10,000배 이상의 시간이 걸려야 하지만, 
        // O(N)인 경우 약 100배 내외의 증가폭을 보여야 합니다.
        expect(durationLarge / durationSmall).toBeLessThan(500); 
    });
});
