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

export enum STATES
{
    INIT,
    IDLE,
    SPINNING
}

type BasicStateMachineStates = InitState | IdleState | SpinningState;

export default class BasicStateMachine extends StateMachine<BaseMachine, BasicStateMachineStates>
{
    constructor(target: BaseMachine)
    {
        super(target);
        this.provideStates([
            new InitState(this),
            new IdleState(this),
            new SpinningState(this),
        ]);
    }

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

    onEnter()
    {
        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: BasicStateMachine;
    public systems: string[];
    constructor(machine: BasicStateMachine)
    {
        super('InitState');
        this.machine = machine;
        this.systems = ['init', 'grid'];
    }

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

    override handleInput(input: any)
    {
        if (!input.flags.init) return;
        this.machine.setState(STATES.IDLE);
    }

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

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

    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: BasicStateMachine;
    public systems: string[];
    constructor(machine: BasicStateMachine)
    {
        super('SpinningState');
        this.machine = machine;
        this.systems = ['spin', 'layering'];
    }

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

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

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