import { Assets, Ticker } from 'pixi.js';
import { Meta, PixiStory, StoryFn } from '@pixi/storybook-renderer';
import HoldAndWinMachine from 'src/slotMachines/HoldAndWinMachine';
import { SlotMachineConfig } from 'src/types/SlotMachineConfig';
import { centerView } from 'src/stories/utils/resize';
import MachineContainer from 'src/stories/utils/MachineContainer';
import { createScreenInputMap } from 'src/stories/utils/createScreenInputMap';
import SlotMultipliersSystem from 'src/systems/SlotMultipliersSystem';
import SlotMultiplierEntity from 'src/entities/SlotMultiplierEntity';
import { STATES } from 'src/states/BasicStateMachine';
import {argTypes, getDefaultArgs} from "src/stories/utils/argTypes";

const args = {
    accelerationTime: 1,
    backCoef: 1.1,
    maxSpeed: 15,
    reelStartDelay: 0.2,
    reelStopDelay: 0.5,
    slotStopDelay: 0,
    spinningDuration: 2,
    blur: false,
    bounce: true
};

/**
 * Creates argTypes with fractional range steps for finer Hold & Win tuning.
 */
const createHoldAndWinArgTypes = (initialArgs: typeof args): ReturnType<typeof argTypes> => {
    const baseArgTypes = argTypes(initialArgs);

    Object.keys(initialArgs).forEach((key) => {

        const descriptor = baseArgTypes[key];
        const control = descriptor?.control;

        if (!control || control.type !== 'range') return;

        baseArgTypes[key] = {
            ...descriptor,
            control: {
                ...control,
                step: control.step && control.step < 1 ? control.step : 0.1,
            },
        };
    });

    return baseArgTypes;
};

const meta: Meta<typeof SlotMultipliersSystem> = {
    title: 'systems/SlotMultipliersSystem',
    tags: ['autodocs'],
    parameters: {
        docs: {
            description: {
                component: 'Displays Spine-based multiplier overlays for every slot based on the slotMultipliers map.',
            },
        },
    },
    argTypes: createHoldAndWinArgTypes(args),
    args: getDefaultArgs(args),
};

export default meta;


/**
 * Updates the multiplier map with random positive values and zeroed blanks.
 */
function randomiseMultipliers(machine: HoldAndWinMachine): void
{
    const total = machine.config.reels * machine.config.slots;
    machine.maps.slotMultipliers = Array.from({ length: total }, () =>
        (Math.random() > 0.6 ? Math.ceil(Math.random() * 10) : 0));
}

export const HoldAndWinMultipliers: StoryFn = (_params, context) => new PixiStory({
    context,
    init: async (view) => {
        Assets.reset();
        await Assets.init({ manifest: 'hold-and-win/manifest.json' });
        await Assets.loadBundle('configs');
        await Assets.loadBundle('symbols');
        await Assets.loadBundle('addons');

        const config: SlotMachineConfig = Assets.get('slot_machine_config');
        const machine = new HoldAndWinMachine(config);
        const container = new MachineContainer(machine);
        container.scale.set(1);
        view.addChild(container);

        context.machine = machine;
        context.prevSpinState = machine.systems.spin.state;

        machine.inputs.initMap = createScreenInputMap(config);
        machine.inputs.screenMap = machine.inputs.initMap;

        const slotMultipliersSystem = new SlotMultipliersSystem(machine);
        slotMultipliersSystem.setSettings({ entityClass: SlotMultiplierEntity });
        machine.systems.slotMultipliers = slotMultipliersSystem;
        // Apply story args to spin system and trigger spin
        machine.systems.spin.setSettings(_params as any);

        const idleState = machine.stateMachine.states[STATES.IDLE];
        if (idleState && !idleState.systems.includes('slotMultipliers'))
        {
            idleState.systems.push('slotMultipliers');
        }

        const spinningState = machine.stateMachine.states[STATES.SPINNING];
        if (spinningState && !spinningState.systems.includes('slotMultipliers'))
        {
            spinningState.systems.push('slotMultipliers');
        }

        randomiseMultipliers(machine);
        machine.inputs.spin = true;

        context.spinDelayMs = 0;

        centerView(view);
    },
    resize: centerView,
    update: () => {
        const machine: HoldAndWinMachine | undefined = context.machine;
        if (!machine) return;

        const dt = Ticker.shared.deltaMS;
        machine.update(dt);

        const spinSystem = machine.systems.spin;
        const prevState = context.prevSpinState ?? spinSystem.state;

        if (prevState !== spinSystem.state)
        {
            if (spinSystem.state === 'starting')
            {
                machine.inputs.spin = false;
            }

            if (spinSystem.state === 'stopped')
            {
                context.spinDelayMs = 500;
            }

            context.prevSpinState = spinSystem.state;
        }

        if ((context.spinDelayMs ?? 0) > 0)
        {
            context.spinDelayMs -= dt;

            if (context.spinDelayMs <= 0)
            {
                randomiseMultipliers(machine);
                machine.inputs.spin = true;
                context.spinDelayMs = 0;
            }
        }
    },
});
