import { evaluateConfirmedState } from '../monitor-state';

const up = { status: 'up' };
const down = { status: 'down' };

// Defaults that match the schema: retries=3, requiredUps=2.
const R_DOWN = 3;
const R_UP = 2;

describe('evaluateConfirmedState', () => {
    describe('cold start (empty history)', () => {
        it('first ever check up -> prev=unknown next=up', () => {
            expect(evaluateConfirmedState([], up, R_DOWN, R_UP)).toEqual({ prev: 'unknown', next: 'up' });
        });
        it('first ever check down -> prev=unknown next=up (pending threshold)', () => {
            expect(evaluateConfirmedState([], down, R_DOWN, R_UP)).toEqual({ prev: 'unknown', next: 'up' });
        });
    });

    describe('going down (requires 3 consecutive downs)', () => {
        it('1 down with no history -> still up', () => {
            expect(evaluateConfirmedState([], down, R_DOWN, R_UP).next).toBe('up');
        });
        it('2 downs total (history=[down], latest=down) -> still up', () => {
            expect(evaluateConfirmedState([down], down, R_DOWN, R_UP).next).toBe('up');
        });
        it('3 downs total (history=[down,down], latest=down) -> CONFIRMED DOWN', () => {
            expect(evaluateConfirmedState([down, down], down, R_DOWN, R_UP)).toEqual({
                prev: 'up',
                next: 'down',
            });
        });
    });

    describe('PR-B.2 up-side hysteresis (the core fix)', () => {
        it('single up after confirmed-down does NOT flip yet', () => {
            // history (DESC, newest first) = 3 confirmed downs. New: up.
            const history = [down, down, down];
            const result = evaluateConfirmedState(history, up, R_DOWN, R_UP);
            expect(result.prev).toBe('down');
            expect(result.next).toBe('down'); // pending recovery
        });

        it('two consecutive ups DO clear to up', () => {
            // history = [up, down, down, down]. New: up. That\'s 2 ups in a row.
            const history = [up, down, down, down];
            const result = evaluateConfirmedState(history, up, R_DOWN, R_UP);
            expect(result.prev).toBe('down'); // single up didn\'t clear
            expect(result.next).toBe('up');
        });

        it('flap (up→down→up) inside the recovery window stays in down', () => {
            // history (DESC) = [down, up, down, down, down]. New: up.
            // The middle up at position 1 of history didn\'t clear
            // (was just 1 up after the down streak). Then a down
            // landed. Now an up: still pending (this is only the 1st
            // up after the most recent down).
            const history = [down, up, down, down, down];
            const result = evaluateConfirmedState(history, up, R_DOWN, R_UP);
            expect(result.next).toBe('down'); // pending recovery
        });

        it('requiredUps=1 reproduces the old single-up clearing behaviour', () => {
            const history = [down, down, down];
            expect(evaluateConfirmedState(history, up, R_DOWN, 1).next).toBe('up');
        });

        it('requiredUps=3 is even more conservative', () => {
            // Need 3 consecutive ups. 2 ups in a row still pending.
            const history = [up, down, down, down];
            expect(evaluateConfirmedState(history, up, R_DOWN, 3).next).toBe('down');
            // 3 ups in a row clears:
            const history3 = [up, up, down, down, down];
            expect(evaluateConfirmedState(history3, up, R_DOWN, 3).next).toBe('up');
        });
    });

    describe('staying down', () => {
        it('confirmed down + another down stays down', () => {
            const history = [down, down, down];
            expect(evaluateConfirmedState(history, down, R_DOWN, R_UP)).toEqual({ prev: 'down', next: 'down' });
        });
    });

    describe('staying up', () => {
        it('confirmed up + another up stays up', () => {
            const history = [up, up, up];
            expect(evaluateConfirmedState(history, up, R_DOWN, R_UP)).toEqual({ prev: 'up', next: 'up' });
        });
    });

    describe('maintenance status is a no-op for the state machine', () => {
        it('maintenance check leaves prev unchanged', () => {
            const history = [up, up, up];
            const m = { status: 'maintenance' };
            expect(evaluateConfirmedState(history, m, R_DOWN, R_UP).next).toBe('up');
        });
    });
});
