import { describe, it, expect } from 'vitest';
import { GameState } from '../GameState';

describe('GameState', () => {
    it('флаги устанавливаются, проверяются и снимаются', () => {
        const s = new GameState();
        expect(s.hasFlag('met_elder')).toBe(false);
        s.setFlag('met_elder');
        expect(s.hasFlag('met_elder')).toBe(true);
        s.clearFlag('met_elder');
        expect(s.hasFlag('met_elder')).toBe(false);
    });

    it('переменные типизированы по геттерам', () => {
        const s = new GameState();
        s.setVar('gold', 42);
        s.setVar('name', 'Ирвин');
        expect(s.getNumber('gold')).toBe(42);
        expect(s.getString('name')).toBe('Ирвин');
        expect(s.getNumber('name')).toBe(0); // не число -> 0
        expect(s.getString('gold')).toBe(''); // не строка -> ''
        expect(s.getVar('missing')).toBeUndefined();
    });

    it('serialize/load сохраняет состояние', () => {
        const s = new GameState();
        s.setFlag('a');
        s.setVar('hp', 7);
        const data = s.serialize();

        const s2 = new GameState();
        s2.load(data);
        expect(s2.hasFlag('a')).toBe(true);
        expect(s2.getNumber('hp')).toBe(7);
        expect(s2.dataVersion).toBe(1);
    });

    it('миграция применяется к сейву старой версии', () => {
        const s = new GameState();
        s.dataVersion = 2;
        s.addMigration((d) => ({
            ...d,
            version: 2,
            vars: { ...d.vars, gold: 100 } // в v2 появилось золото
        }));

        s.load({ version: 1, flags: ['x'], vars: {} });
        expect(s.dataVersion).toBe(2);
        expect(s.getNumber('gold')).toBe(100);
        expect(s.hasFlag('x')).toBe(true);
    });

    it('две миграции применяются по порядку, по одной на версию', () => {
        const s = new GameState();
        s.dataVersion = 3;
        s.addMigration((d) => ({ ...d, version: 2, flags: [...d.flags, 'step1'] }));
        s.addMigration((d) => ({ ...d, version: 3, flags: [...d.flags, 'step2'] }));

        s.load({ version: 1, flags: [], vars: {} });
        expect(s.allFlags).toEqual(['step1', 'step2']);
    });

    it('миграция без повышения version не применяется дважды', () => {
        const s = new GameState();
        s.dataVersion = 2;
        // Миграция нарушает контракт (забыла version) — цикл всё равно
        // не даёт следующей миграции испортить данные.
        s.addMigration((d) => ({ ...d, vars: { ...d.vars, n: Number(d.vars.n ?? 0) + 1 } }));
        s.addMigration((d) => ({ ...d, version: 2, flags: ['done'] }));

        s.load({ version: 1, flags: [], vars: {} });
        expect(s.getNumber('n')).toBe(1);
        expect(s.hasFlag('done')).toBe(true);
    });

    it('reset очищает всё', () => {
        const s = new GameState();
        s.setFlag('a');
        s.setVar('b', 1);
        s.reset();
        expect(s.allFlags).toEqual([]);
        expect(s.getVar('b')).toBeUndefined();
    });
});