import AutoGameModel, {
    AnyWinCondition,
    type AutoGameConfig,
    BalanceDecreaseCondition,
    BalanceIncreaseCondition,
    BonusGameWonCondition,
    SingleWinExceedsCondition,
    SpinsExceedLimit,
} from './AutoGameModel';
import {
    describe,
    expect,
    it,
} from '@jest/globals';

describe('AutoGame', () =>
{
    it('should initialize with the correct configuration', () =>
    {
        const config: AutoGameConfig = {
            issued: 10,
            startingBalance: 1000,
            advanced: {
                anyWin: true,
                balanceDecrease: { enabled: true, threshold: 50 },
            },
        };

        const autoGame = new AutoGameModel(config);

        expect(autoGame.spinCount.issued).toBe(10);
        expect(autoGame.spinCount.current).toBe(0);
        expect(autoGame.startingBalance).toBe(1000);
        expect(autoGame.isActive()).toBe(true);
    });

    it('should return false for isActive when issued spins are 0', () =>
    {
        const autoGame = new AutoGameModel({ issued: 0 });

        expect(autoGame.isActive()).toBe(false);
    });

    it('should increment spin count on startSpin', () =>
    {
        const autoGame = new AutoGameModel({ issued: 5 });

        autoGame.startSpin();
        expect(autoGame.spinCount.current).toBe(1);

        autoGame.startSpin();
        expect(autoGame.spinCount.current).toBe(2);
    });

    it('should throw an error when exceeding issued spins', () =>
    {
        const autoGame = new AutoGameModel({ issued: 2 });

        autoGame.startSpin();
        autoGame.startSpin();

        expect(() => autoGame.startSpin()).toThrow('You have reached the limit of issued spins.');
        expect(autoGame.isActive()).toBe(false);
    });

    it('should handle infinite spins correctly', () =>
    {
        const autoGame = new AutoGameModel({ issued: Infinity });

        expect(autoGame.isActive()).toBe(true);

        autoGame.startSpin();
        expect(autoGame.spinCount.current).toBe(1);

        autoGame.startSpin();
        expect(autoGame.spinCount.current).toBe(2);

        expect(autoGame.isActive()).toBe(true);
    });

    it('should stop the game when a stop condition is met', () =>
    {
        const config: AutoGameConfig = {
            issued: 10,
            startingBalance: 1000,
            advanced: {
                anyWin: true,
            },
        };

        const autoGame = new AutoGameModel(config);

        autoGame.startSpin();
        autoGame.endSpin(1000, 100, false);

        expect(autoGame.isActive()).toBe(false);
    });

    it('should not stop the game if conditions are not met', () =>
    {
        const config: AutoGameConfig = {
            issued: 10,
            startingBalance: 1000,
            advanced: {
                anyWin: true,
            },
        };

        const autoGame = new AutoGameModel(config);

        autoGame.startSpin();
        autoGame.endSpin(1000, 0, false);

        expect(autoGame.isActive()).toBe(true);
    });

    it('should calculate balance change correctly in endSpin', () =>
    {
        const config: AutoGameConfig = {
            issued: 5,
            startingBalance: 1000,
            advanced: {
                balanceDecrease: { enabled: true, threshold: 50 },
            },
        };

        const autoGame = new AutoGameModel(config);

        autoGame.startSpin();
        autoGame.endSpin(900, 0, false);

        expect(autoGame.isActive()).toBe(false);
    });
});

describe('StopConditions', () =>
{
    it('should correctly evaluate SpinsExceedLimit', () =>
    {
        const condition = new SpinsExceedLimit(true);

        const spinCount = { current: 5, issued: 3 };

        expect(condition.isMet({ balanceChange: 0, bonusGameWon: false, currentWin: 0, spinCount })).toBe(true);

        const spinCountInfinite = { current: 5, issued: Infinity };

        expect(condition.isMet({ balanceChange: 0, bonusGameWon: false, currentWin: 0, spinCount: spinCountInfinite })).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet({ balanceChange: 0, bonusGameWon: false, currentWin: 0, spinCount })).toBe(false);
    });

    it('should correctly evaluate AnyWinCondition', () =>
    {
        const condition = new AnyWinCondition(true);

        const gameStateWin = { currentWin: 100, bonusGameWon: false, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateWin)).toBe(true);

        const gameStateNoWin = { currentWin: 0, bonusGameWon: false, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateNoWin)).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet(gameStateWin)).toBe(false);
    });

    it('should correctly evaluate BonusGameWonCondition', () =>
    {
        const condition = new BonusGameWonCondition(true);

        const gameStateBonusWon = { currentWin: 0, bonusGameWon: true, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateBonusWon)).toBe(true);

        const gameStateNoBonus = { currentWin: 0, bonusGameWon: false, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateNoBonus)).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet(gameStateBonusWon)).toBe(false);
    });

    it('should correctly evaluate SingleWinExceedsCondition', () =>
    {
        const condition = new SingleWinExceedsCondition(true, 50);

        const gameStateWinExceeds = { currentWin: 100, bonusGameWon: false, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateWinExceeds)).toBe(true);

        const gameStateWinBelow = { currentWin: 30, bonusGameWon: false, balanceChange: 0, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateWinBelow)).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet(gameStateWinExceeds)).toBe(false);
    });

    it('should correctly evaluate BalanceIncreaseCondition', () =>
    {
        const condition = new BalanceIncreaseCondition(true, 100);

        const gameStateBalanceUp = { currentWin: 0, bonusGameWon: false, balanceChange: 150, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateBalanceUp)).toBe(true);

        const gameStateBalanceBelow = { currentWin: 0, bonusGameWon: false, balanceChange: 50, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateBalanceBelow)).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet(gameStateBalanceUp)).toBe(false);
    });

    it('should correctly evaluate BalanceDecreaseCondition', () =>
    {
        const condition = new BalanceDecreaseCondition(true, 50);

        const gameStateBalanceDown = { currentWin: 0, bonusGameWon: false, balanceChange: -100, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateBalanceDown)).toBe(true);

        const gameStateBalanceAbove = { currentWin: 0, bonusGameWon: false, balanceChange: -30, spinCount: { current: 0, issued: 0 } };

        expect(condition.isMet(gameStateBalanceAbove)).toBe(false);

        condition.isEnabled = false;
        expect(condition.isMet(gameStateBalanceDown)).toBe(false);
    });
});
