import {
    mergeDailyBuckets,
    fillDailySeries,
    type DailyRow,
} from '../analytics-aggregation';

describe('analytics-aggregation pure helpers', () => {
    describe('mergeDailyBuckets', () => {
        it('keys raw + hourly rows by day and sums overlapping fields via addAgg', () => {
            const raw: DailyRow[] = [
                { day: '2026-05-30', total: 10, up: 9, latSum: 900, latCount: 9 },
            ];
            const hourly: DailyRow[] = [
                { day: '2026-05-20', total: 24, up: 24, latSum: 4800, latCount: 24 },
            ];
            const m = mergeDailyBuckets(raw, hourly);
            expect(m.size).toBe(2);
            expect(m.get('2026-05-30')).toEqual({ total: 10, up: 9, latSum: 900, latCount: 9 });
            expect(m.get('2026-05-20')).toEqual({ total: 24, up: 24, latSum: 4800, latCount: 24 });
        });

        it('defensively sums when the same day appears in both tiers (no silent overwrite)', () => {
            const raw: DailyRow[] = [{ day: '2026-05-25', total: 5, up: 5, latSum: 500, latCount: 5 }];
            const hourly: DailyRow[] = [{ day: '2026-05-25', total: 3, up: 2, latSum: 200, latCount: 2 }];
            const m = mergeDailyBuckets(raw, hourly);
            expect(m.size).toBe(1);
            expect(m.get('2026-05-25')).toEqual({ total: 8, up: 7, latSum: 700, latCount: 7 });
        });

        it('returns an empty map for empty inputs', () => {
            expect(mergeDailyBuckets([], []).size).toBe(0);
        });
    });

    describe('fillDailySeries', () => {
        it('emits one cell per day across the range, filling gaps with zero-rows', () => {
            const start = new Date('2026-05-28T00:00:00Z');
            const m = new Map([
                ['2026-05-28', { total: 10, up: 10, latSum: 1000, latCount: 10 }],
                // 2026-05-29 missing -> gap
                ['2026-05-30', { total: 4, up: 2, latSum: 200, latCount: 2 }],
            ]);
            const series = fillDailySeries(m, start, 2); // inclusive endpoints -> 3 cells: 05-28..05-30

            expect(series.map((c) => c.date)).toEqual(['2026-05-28', '2026-05-29', '2026-05-30']);

            expect(series[0]).toMatchObject({ totalChecks: 10, upChecks: 10, downChecks: 0, uptimePercent: 100, avgLatency: 100 });
            // gap day: no data, totals zero, marked as no-data
            expect(series[1]).toMatchObject({ totalChecks: 0, upChecks: 0, downChecks: 0, hasData: false });
            // partial-up day: 2/4 = 50%
            expect(series[2]).toMatchObject({ totalChecks: 4, upChecks: 2, downChecks: 2, uptimePercent: 50, avgLatency: 100 });
        });

        it('flags populated days hasData:true and gap days hasData:false', () => {
            const start = new Date('2026-05-29T00:00:00Z');
            const m = new Map([['2026-05-29', { total: 2, up: 1, latSum: 50, latCount: 1 }]]);
            const series = fillDailySeries(m, start, 1);
            expect(series).toHaveLength(2); // day 0 and day 1 (inclusive range)
            expect(series[0].hasData).toBe(true);
            expect(series[1].hasData).toBe(false);
        });
    });
});
