import BaseMachine from '../slotMachines/BaseMachine';
import { State, StateMachine } from '@popiplay/state-machine';

export enum STATES
{
    INIT,
    IDLE,
    SPINNING,
    ALL_WINNING_SYMBOLS,
    CELEBRATE_SYMBOLS,
    ENDING_ROUND,
    WINNING_LINES_LOOP,
}

type ClassicReelsStateMachineStates = InitState | IdleState | SpinningState | AllWinningSymbolsState | CelebrateSymbolsState | EndingRoundState | WinningLinesLoopState;

export default class ClassicReelsStateMachine extends StateMachine<BaseMachine, ClassicReelsStateMachineStates>
{
    constructor(target: BaseMachine)
    {
        super(target);
        this.provideStates([
            new InitState(this),
            new IdleState(this),
            new SpinningState(this),
            new AllWinningSymbolsState(this),
            new CelebrateSymbolsState(this),
            new EndingRoundState(this),
            new WinningLinesLoopState(this),
        ]);
    }

    override update(dt: number)
    {
        super.update(dt);
        this.currentState.systems.forEach((systemId) =>
        {
            this.target.systems[systemId].update(dt);
        });
    }

    onEnter()
    {
        console.log("Enter: ", this.currentState.name)
        this.currentState.systems.forEach((systemId) =>
        {
            this.target.systems[systemId].onEnter();
        });
    }

    onLeave()
    {
        this.currentState.systems.forEach((systemId) =>
        {
            this.target.systems[systemId].onLeave();
        });
    }

    init()
    {
        this.setState(STATES.INIT);
    }
}

class InitState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('InitState');
        this.machine = machine;
        this.systems = ['init', 'grid', 'blurSymbols'];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(input: any)
    {
        if (!input.flags.init) return;
        if (input.inputs.wins)
        {
            this.machine.setState(STATES.ALL_WINNING_SYMBOLS);
        }
        else if (input.inputs.celebrateSymbolIndexes?.length > 0)
        {
            this.machine.setState(STATES.CELEBRATE_SYMBOLS);
        }
        else
        {
            this.machine.setState(STATES.ENDING_ROUND);
        }
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class IdleState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('IdleState');
        this.machine = machine;
        this.systems = [
            'grid',
            'idle',
            'layering',
            'interactive',
            'resetWinningSymbols',
            'resetTinting',
            'tinting',
            'winLinesResetIncrement',
            'blurSymbols'
        ];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (target.inputs.spin === true)
        {
            this.machine.setState(STATES.SPINNING);
        }
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class SpinningState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('SpinningState');
        this.machine = machine;
        this.systems = [
            'spin',
            'layering',
            'resetWinningSymbols',
            'resetTinting',
            'tinting',
            'winLinesResetIncrement',
            'blurSymbols'
        ];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (!this.systems.every((key) => target.systems[key].state === 'stopped')) return;
        if (target.inputs.wins)
        {
            this.machine.setState(STATES.ALL_WINNING_SYMBOLS);
        }
        else if (target.inputs.celebrateSymbolIndexes?.length > 0)
        {
            this.machine.setState(STATES.CELEBRATE_SYMBOLS);
        }
        else
        {
            this.machine.setState(STATES.ENDING_ROUND);
        }
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class AllWinningSymbolsState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('AllWinningSymbolsState');
        this.machine = machine;
        this.systems = [
            'resetWinningSymbols',
            'allWinSymbols',
            'allWinLinesSet',
            'winningSymbolsAnim',
            'tintWinningSymbolsAnim',
            'tinting',
            'winLinesAnimations',
            'displayTotalLinesWin',
            'blurSymbols'
        ];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (!this.systems.every((key) => target.systems[key].state === 'stopped')) return;
        if (target.inputs.celebrateSymbolIndexes?.length > 0)
        {
            this.machine.setState(STATES.CELEBRATE_SYMBOLS);
        } else
        {
            this.machine.setState(STATES.ENDING_ROUND);
        }
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class CelebrateSymbolsState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('CelebrateSymbolsState');
        this.machine = machine;
        this.systems = ['celebrateSymbols', 'tinting', 'blurSymbols'];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (!this.systems.every((key) => target.systems[key].state === 'stopped')) return;
        this.machine.setState(STATES.ENDING_ROUND);
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class EndingRoundState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('EndingRoundState');
        this.machine = machine;
        this.systems = ['blockExitState', 'blurSymbols'];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (!this.systems.every((key) => target.systems[key].state === 'stopped')) return;
        if (target.inputs.spin) {
            this.machine.setState(STATES.SPINNING);
        }
        else if (target.inputs.wins)
        {
            this.machine.setState(STATES.WINNING_LINES_LOOP);
        } else
        {
            this.machine.setState(STATES.IDLE);
        }
    }

    override leave()
    {
        this.machine.onLeave();
    }
}

class WinningLinesLoopState extends State
{
    private machine: ClassicReelsStateMachine;
    public systems: string[];
    constructor(machine: ClassicReelsStateMachine)
    {
        super('WinningLinesLoopState');
        this.machine = machine;
        this.systems = [
            'resetWinningSymbols',
            'winLinesIncrementing',
            'setWinLineSymbols',
            'setWinLine',
            'winningSymbolsAnim',
            'tintWinningSymbolsAnim',
            'tinting',
            'interactive',
            'winLinesAnimations',
            'displayLineWin',
            'blurSymbols'
        ];
    }

    override enter()
    {
        this.machine.onEnter();
    }

    override handleInput(target: BaseMachine)
    {
        if (target.inputs.spin === true)
        {
            this.machine.setState(STATES.SPINNING);

            return;
        }

        if (!this.systems.every((key) => target.systems[key].state === 'stopped')) return;
        this.machine.setState(STATES.WINNING_LINES_LOOP);
    }

    override leave()
    {
        this.machine.onLeave();
    }
}
