/**
 * @typedef {object} PhaserScene
 * @property {(x:number, y:number, font:string, text:string) => PhaserBitmapText} add
 */

/**
 * @typedef {object} PhaserBitmapText
 * @property {number} width
 * @property {number} scale
 * @property {(v:number) => void} setAlpha
 * @property {(v:boolean) => void} setVisible
 * @property {(v:number) => void} setScale
 * @property {(v:number) => void} setDepth
 * @property {(v:number|string) => void} setText
 * @property {(v:number) => void} setOrigin
 * @property {(v:number, w:number) => void} setOriginXY
 * @property {number} x
 * @property {number} y
 * @property {number} letterSpacing
 * @property {() => any} getTextBounds
 */

class AnimatedAmountX
{
    /**
     * @param {PhaserScene} scene
     * @param {number} x
     * @param {number} y
     * @param {string} bmFont
     * @param {boolean} useUnits
     * @param {number=} maxlength
     */
    constructor(scene, x, y, bmFont, useUnits, maxlength = undefined)
    {
        this.x = x;
        this.y = y;

        this.useUnits = useUnits;

        /** @type {PhaserBitmapText} */
        this.bmText = scene.add.bitmapText(x, y, bmFont, "");

        this.int_max = 4294967295;

        this.first_ = 0.0;
        this.last_ = this.int_max;
        this.t_ = 0.0;
        this.speed = 1200.0;
        this.precision = 2;

        this.visible = true;
        this.updateEnable = false;
        this.timer = 0;

        /** @type {(() => void) | null} */
        this.eventHandler = null;
        this.canFireEvent = false;

        this.maxlength = maxlength;

        return this;
    }

    reset (v)
    {
        this.first_ = parseFloat(String(v));
        this.last_ = v;
        this.t_ = 1.0;

        this.setText(v);

        this.canFireEvent = true;

        return this;
    }

    value ()
    {
        return Math.round(this.value2());
    }

    value2 ()
    {
        if (this.last_ === this.int_max)
        {
            return this.first_;
        }

        const t = this.t_ - 2.0 * this.t_ * (this.t_ - 0.5) * (this.t_ - 1.0);

        return this.first_ + t * (this.last_ - this.first_);
    }

    getTextBounds ()
    {
        return this.bmText.getTextBounds();
    }

    setAlpha (v)
    {
        this.bmText.setAlpha(v);
        
        return this;
    }

    setVisible (v)
    {
        this.visible = v;
        
        this.bmText.setVisible(v);

        return this;
    }

    setUpdateEnable (v)
    {
        this.updateEnable = v;

        return this;
    }

    setScale (v = 1.0)
    {
        if (this.maxlength !== undefined && this.bmText.width > this.maxlength)
        {
            this.bmText.setScale((this.maxlength / this.bmText.width) * v);
        }
        else
        {
            this.bmText.setScale(v);
        }

        return this;
    }

    getScale ()
    {
        return this.bmText.scale;
    }

    setSpacing (v)
    {
        this.bmText.letterSpacing = v;
        
        return this;
    }

    setPosition (x, y)
    {
        this.x = x;
        this.y = y;

        this.bmText.x = x;
        this.bmText.y = y;

        return this;
    }

    setOrigin (x)
    {
        this.bmText.setOrigin(x);
        
        return this;
    }

    setOriginXY (x, y)
    {
        this.bmText.setOrigin(x, y);
        
        return this;
    }

    setSpeed (v)
    {
        if (v > 0)
        {
            this.speed = v;
        }
        
        return this;
    }

    setText (v)
    {
        this.bmText.setText("x" + v);

        if (this.maxlength !== undefined)
        {
            this.setScale();
        }

        return this;
    }

    setDepth (v)
    {
        this.bmText.setDepth(v);
        
        return this;
    }

    setPrecision (v)
    {
        this.precision = v;
        
        this.setText(this.value());
        
        return this;
    }

    setScrollFactor (v)
    {
        this.bmText.setScrollFactor(v);

		return this;
    }

    fireEvent (v)
    {
        this.canFireEvent = v;
        
        return this;
    }

    /**
     * @param {number} delta
     * @param {number} target
     */
    update (delta, target)
    {
        if (!this.visible && !this.updateEnable)
        {
            return;
        }

        if (this.value() === target)
        {
            return;
        }

        if (this.last_ === this.int_max)
        {
            this.reset(target);
            return;
        }

        if (this.last_ !== target)
        {
            this.first_ = this.value2();
            this.last_ = target;
            this.t_ = 0.0;
        }

        this.t_ += delta / this.speed;

        if (this.t_ > 1.0)
        {
            this.t_ = 1.0;
        }

        this.setText(this.value());

        if (
            this.visible &&
            this.value() === target &&
            this.eventHandler !== null &&
            this.canFireEvent
        )
        {
            this.eventHandler();

            this.canFireEvent = false;
        }
    }
}
