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

/**
 * Lightweight overlay entity for slot multipliers backed by a Spine animation.
 */
export default class SlotMultiplierEntity extends Container implements Updatable, CanPlayIn, CanPlayOut
{
    private spine: Spine;
    private assetKey: string;
    private shown: boolean;
    private label: Text;
    private valueInternal = 0;

    constructor(assetKey: string = 'slot_multiplier')
    {
        super();
        this.assetKey = assetKey;
        this.shown = false;
        this.spine = this.createSpine();
        this.visible = false;
        this.addChild(this.spine);
        this.label = this.createLabel();
        this.attachLabel();
        this.registerOutListener();
    }

    /**
     * Exposes current visibility state used by systems to prevent redundant transitions.
     */
    public isShown(): boolean
    {
        return this.shown;
    }

    /**
     * Plays the "in" animation and reveals the entity.
     */
    public in(): ITrackEntry
    {
        this.visible = true;
        this.shown = true;

        return this.spine.state.setAnimation(0, 'in', false);
    }

    /**
     * Plays the "out" animation and keeps the entity visible until completion.
     */
    public out(): ITrackEntry
    {
        this.shown = false;

        return this.spine.state.setAnimation(0, 'out', false);
    }

    /**
     * Current multiplier value displayed by the overlay text.
     */
    public get value(): number
    {
        return this.valueInternal;
    }

    /**
     * Updates the overlay text with the provided multiplier value.
     */
    public set value(value: number)
    {
        this.valueInternal = value;
        this.label.text = Number.isFinite(value) ? value.toString() + "x" : '';
    }

    /**
     * Updates the underlying Spine animation.
     */
    public update(dt: number): void
    {
        this.spine.update(dt * 0.001);
    }

    /**
     * Creates the Spine instance for the multiplier overlay.
     */
    private createSpine(): Spine
    {
        const asset = Assets.get(this.assetKey);
        const spine = new Spine(asset.spineData);
        spine.autoUpdate = false;

        return spine;
    }

    /**
     * Creates a red, centred text label for displaying the multiplier value.
     */
    private createLabel(): Text
    {
        const text = new Text('', {
            fill: 0xffffff,
            fontSize: 24,
        });
        text.anchor.set(0.5);
        text.scale.set(1, -1)

        return text;
    }

    /**
     * Attaches the label to the Spine placeholder slot container.
     */
    private attachLabel(): void
    {
        const placeholderIndex = this.findPlaceholderSlotIndex();
        if (placeholderIndex < 0)
        {
            this.addChild(this.label);
            return;
        }

        const container = this.spine.slotContainers[placeholderIndex];
        if (!container)
        {
            this.addChild(this.label);
            return;
        }

        container.addChild(this.label);
    }

    /**
     * Resolves the placeholder slot index from the Spine skeleton.
     */
    private findPlaceholderSlotIndex(): number
    {
        return this.spine.skeleton.findSlotIndex('placeholder');
    }

    /**
     * Hides the container once the "out" animation completes.
     */
    private registerOutListener(): void
    {
        this.spine.state.addListener({
            complete: (entry: ITrackEntry) =>
            {
                if (entry.animation.name !== 'out') return;

                this.visible = false;
            },
        });
    }
}
