import { Assets, Container } from 'pixi.js';
import { IBone, Spine } from 'pixi-spine';
import { Updatable } from '../types/Entity';
import { ITrackEntry } from '../types/ITrackEntry';

interface IBoneExtended extends IBone
{
    x: number;
    y: number;
}

/**
 * @class WinLine
 * @extends Container
 * @implements Updatable
 * @description
 * The `WinLine` class represents a visual line in a slot machine game that can be animated to show winning lines.
 * It extends the `Container` class and implements the `Updatable` interface.
 * The class uses Spine animations to display the win line and provides methods to set the line's position,
 * update the animation state, and trigger idle and win animations.
 */
export default class WinLine extends Container implements Updatable
{
    spine: Spine;
    slotSize: { x: number, y: number };

    constructor()
    {
        super();
        this.spine = new Spine(Assets.get('win_line').spineData);
        this.spine.autoUpdate = false;
        this.spine.state.timeScale = 1;
        this.spine.alpha = 0.8;
        this.idle();
        this.addChild(this.spine);

        this.spine.state.addListener({
            event: (_, event) =>
            {
                if (event.data.name === 'end')
                {
                    this.idle();
                }
            }
        });

        this.zIndex = 10100;
        this.slotSize = { x: 200, y: 200 };
        this.scale.set(0.52);
        this.position.set(0, this.slotSize.y * 0.5 * this.scale.y);
    }

    /**
     * Sets the positions of the control bones based on the provided line map.
     * @param lineMap - An array of numbers representing the slot indices for each reel.
     * @returns void
     */
    set(lineMap: number[]): void
    {
        (this.spine.skeleton.findBone('control_0') as IBoneExtended).y = -lineMap[0] * this.slotSize.y;
        (this.spine.skeleton.findBone('control_6') as IBoneExtended).y = -lineMap[lineMap.length - 1] * this.slotSize.y;
        lineMap.forEach((slotIndex: number, reelIndex: number) =>
        {
            const control = this.spine.skeleton.findBone(`control_${reelIndex + 1}`) as IBoneExtended;

            if (!control) return;
            control.y = -slotIndex * this.slotSize.y;
        });
    }

    /**
     * Updates the spine animation with the given delta time.
     * @param dt - The delta time in milliseconds.
     * @returns void
     */
    update(dt: number): void
    {
        this.spine.update(dt * 0.001);
    }

    /**
     * Sets the animation to 'idle' on the spine state.
     * @returns {ITrackEntry} The track entry of the animation.
     */
    idle(): ITrackEntry
    {
        return this.spine.state.setAnimation(0, 'idle', false);
    }

    /**
     * Triggers the 'win' animation on the spine state.
     * @returns {ITrackEntry} The track entry of the animation.
     */
    win(): ITrackEntry
    {
        return this.spine.state.setAnimation(0, 'win', false);
    }
}
