import WebGLWinLine from '../entities/WebGLWinLine';
import BaseMachine from '../slotMachines/BaseMachine';
import BaseSystem from '../systems/BaseSystem';

export interface WinLinesAnimationsSystemSettings
{
    zIndex: number,
    lineClass: typeof WebGLWinLine,
}

export default class WinLinesAnimationsSystem extends BaseSystem<WinLinesAnimationsSystemSettings>
{
    public state: 'watch' | 'animating' | 'stopped' = 'stopped';

    private lines: WebGLWinLine[] = [];

    static override requiredInputs: string[] = ['wins'];
    static override sharedSystemData: string[] = ['animateLines'];

    static defaultSettings: WinLinesAnimationsSystemSettings = {
        zIndex: 20,
        lineClass: WebGLWinLine,
    };

    constructor(machine: BaseMachine)
    {
        super(machine);
        this.setSettings(WinLinesAnimationsSystem.defaultSettings);
    }

    override onEnter()
    {
        this.handleAnimateLinesData();
    }

    override update(_dt: number)
    {
        if (this.state === 'stopped') return;
        if (this.lines.every((line) =>
        {
            if (!line) return true;

            return line.state === 'stopped';
        }))
        {
            this.state = 'stopped';
        }
    }

    override onLeave()
    {
        this.resetAnimateLinesData();
    }

    private handleAnimateLinesData()
    {
        this.machine.sharedSystemData.animateLines.forEach((lineIndex: number) =>
        {
            const lineMap = this.machine.config.lines

            if (!lineMap)
            {
                throw new Error(`Line ${lineIndex} not found`);
            }
            if (!this.lines[lineIndex])
            {
                this.createLine(lineIndex);
            }
            this.lines[lineIndex].play();
        });
        this.state = 'animating';
    }

    private createLine(lineIndex: number)
    {
        if (!this.settings.lineClass)
        {
            throw new Error(`Line class isn't defined in settings`);
        }
        const lineMap:number[] = this.machine.config.lines[lineIndex];
        const points: number[][] = lineMap.map((slot, reel):number[] => [reel, slot]);
        points.unshift([-1, lineMap[0]]);
        points.push([lineMap.length, lineMap[lineMap.length - 1]]);
        const slotWidth = this.machine.utils.grid.getSlotWidth();
        const slotHeight = this.machine.utils.grid.getSlotHeight();
        const line = new this.settings.lineClass(points, slotWidth, slotHeight);

        line.zIndex = this.settings.zIndex;
        this.machine.addChild(line);
        this.lines[lineIndex] = line;
    }

    resetAnimateLinesData()
    {
        this.machine.sharedSystemData.animateLines = [];
        this.lines.forEach((line) =>
        {
            if (!line) return;
            line.state = 'stopped';
        });
    }
}
