import { randInt } from "@common/utils";
import Entity from "./entity";

export enum SpinnerAction {
    RUN = 1,
    BITE = 2,
    MELEE = 3,
    SHOOT = 4,
};

export type SpinnerListener = (action: SpinnerAction) => void;

export default class Spinner extends Entity {
    private readonly probabilities = [0.3, 0.3, 0.2, 0.2];
    private readonly colors = ['yellow', 'green', 'blue', 'red'];
    private readonly symbols = ['🏃‍♂️', '🧟‍♂️', '🔪', '🎯'];
    private readonly startAngle = -Math.PI / 2 - this.probabilities[0] * 2 * Math.PI;

    private angle = -Math.PI / 2;
    private nextAngle = this.angle;
    private fired = true;
    private listeners = new Set<SpinnerListener>();

    protected override draw(ctx: CanvasRenderingContext2D) {
        ctx.scale(0.9, 0.9);
        ctx.translate(0.05, 0.05);

        ctx.fillStyle = 'white';

        ctx.beginPath();
        ctx.arc(0.5, 0.5, 0.5, 0, Math.PI * 2);
        ctx.fill();


        ctx.lineCap = 'butt';
        ctx.fillStyle = 'black';
        ctx.font = '0.1px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.lineWidth = 0.2;

        let angle = this.startAngle;
        for (let i = 0; i < this.probabilities.length; i++) {
            ctx.strokeStyle = this.colors[i];
            ctx.beginPath();
            const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;
            ctx.arc(0.5, 0.5, 0.4, angle, nextAngle);
            ctx.stroke();

            const center = (angle + nextAngle) / 2;
            ctx.fillText(`${i + 1}`, 0.5 + Math.cos(center) * 0.4, 0.5 + Math.sin(center) * 0.4);
            ctx.fillText(this.symbols[i], 0.5 + Math.cos(center) * 0.18, 0.5 + Math.sin(center) * 0.18);

            angle = nextAngle;
        }

        ctx.lineCap = 'round';
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 0.01;

        angle = this.startAngle;
        for (let i = 0; i < this.probabilities.length; i++) {
            const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;

            ctx.beginPath();
            ctx.moveTo(0.5, 0.5);
            ctx.lineTo(0.5 + Math.cos(angle) * 0.49, 0.5 + Math.sin(angle) * 0.49);
            ctx.stroke();

            angle = nextAngle;
        }
        ctx.beginPath();
        ctx.arc(0.5, 0.5, 0.3, 0, Math.PI * 2);
        ctx.stroke();

        ctx.lineWidth = 0.03;
        ctx.beginPath();
        ctx.arc(0.5, 0.5, 0.49, 0, Math.PI * 2);
        ctx.moveTo(0.5, 0.5);
        ctx.lineTo(0.5 + Math.cos(this.angle) * 0.4, 0.5 + Math.sin(this.angle) * 0.4);
        ctx.stroke();
    }

    public override update(dt: number) {
        if (this.fired) return;
        if (this.nextAngle - this.angle <= 0.1) {
            this.fire();
            return;
        }

        this.angle += (this.nextAngle - this.angle) * dt;
    }

    public override onClick() {
        this.spin();
    }

    public spin() {
        if (!this.fired) return;

        this.fired = false;
        this.nextAngle = this.angle + (randInt(5, 10) + Math.random()) * 2 * Math.PI;
    }

    public stop() {
        this.fired = true;
    }

    public addListener(listener: SpinnerListener) {
        this.listeners.add(listener);
    }

    public removeListener(listener: SpinnerListener) {
        this.listeners.delete(listener);
    }

    private fire() {
        if (this.fired) return;
        this.fired = true;

        let checkAngle = this.angle % (Math.PI * 2);

        for (let a = 0; a < 2; a++) {
            let angle = (this.startAngle + Math.PI * 2) % (Math.PI * 2);
            for (let i = 0; i < this.probabilities.length; i++) {
                const nextAngle = angle + this.probabilities[i] * 2 * Math.PI;

                if (angle <= checkAngle && checkAngle <= nextAngle) {
                    this.listeners.forEach(l => l(i + 1));
                    return;
                }

                angle = nextAngle;
            }
            checkAngle += Math.PI * 2;
        }
    }
}
