import AllWinningSymbolSystem from '../systems/AllWinningSymbolSystem';
import ValuableReelSymbol from '../entities/ValuableReelSymbol';
import ClassicReelsStateMachine from '../states/ClassicReelsStateMachine';
import CelebrateSystem from '../systems/CelebrateSystem';
import GridSystem from '../systems/GridSystem';
import IdleSystem from '../systems/IdleSystem';
import InitSystem from '../systems/InitSystem';
import InteractiveGridSystem from '../systems/InteractiveGridSystem';
import LayeringSystem from '../systems/LayeringSystem';
import ReelsSpinSystem from '../systems/ReelsSpinSystem';
import ResetTintSystem from '../systems/ResetTintSystem';
import ResetWinningSymbolsSystem from '../systems/ResetWinningSymbolsSystem';
import SetAllWinLinesSystem from '../systems/SetAllWinLinesSystem';
import SetCurrentWinLinesSystem from '../systems/SetCurrentWinLinesSystem';
import SetWinningLineSymbolsSystem from '../systems/SetWinningLineSymbolsSystem';
import TintingSymbolsSystem from '../systems/TintingSymbolsSystem';
import WinLinesAnimationsSystem from '../systems/WinLinesAnimationsSystem';
import WinningLinesIncrementSystem from '../systems/WinningLinesIncrementSystem';
import WinningLinesResetIncrementSystem from '../systems/WinningLinesResetIncrementSystem';
import WinningSymbolAnimationsSystem from '../systems/WinningSymbolAnimationsSystem';
import WinningSymbolTintingSystem from '../systems/WinningSymbolTintingSystem';
import GridUtils from '../utils/GridUtils';
import BaseMachine from './BaseMachine';
import DisplayTotalLinesWinSystem from "../systems/DisplayTotalLinesWinSystem";
import DisplayLineWinValueSystem from "../systems/DisplayLineWinValueSystem";
import BlockExitStateSystem from "../systems/BlockExitStateSystem";
import MaskingSystem from '../systems/MaskingSystem';
import BlurSymbolsSystem from '../systems/BlurSymbolsSystem';

/**
 * @class ReelsMachine
 * @extends BaseMachine
 * @description The main class for managing slot machine reels. Initializes and maintains state, systems,
 * and utilities to control the reel behavior, from initialization to spinning and stopping.
 */
export default class ReelsMachine extends BaseMachine
{
    public stateMachine: ClassicReelsStateMachine;

    /**
     * Initializes the reel machine with configuration settings.
     * Sets up inputs, flags, maps, utilities, systems, and the state machine.
     * @param {object} config - Configuration settings for the machine.
     */
    constructor(config: any)
    {
        super(config);
        this.initialize();
        this.stateMachine.init();
    }

    /**
     * Initializes the inputs required for the reel machine.
     * `initMap` is used for initial symbol mapping, `spin` for triggering spins,
     * and `screenMap` for tracking symbol positions on the screen.
     */
    protected override createInputs(): void
    {
        this.inputs = {
            initMap: null,
            spin: false,
            screenMap: null,
            turbo: false,
            fastStop: false,
            turboForced: false,
            wins: null,
            blockExitState: false,
        };
    }

    /** Sets up flags to track the machine's state, such as whether initialization has completed. */
    protected override createFlags(): void
    {
        this.flags = {
            init: false,
            isSpinning: false,
        };
    }

    protected override createSharedData(): void
    {
        this.sharedSystemData = {
            spinSystemState: 'stopped',
            currentStoppingReel: 0,
            reelsStates: [],
            currentWinIndex: 0,
            animateLines: [],
            anticipatingSymbolsTests: [],
        };
    }

    /** Sets up maps used by the machine, including `symbols`, which holds the names of the symbols on reels. */
    protected override createMaps(): void
    {
        this.maps = {
            symbols: [],
            stickySymbols: [],
            preventReelStop: [],
            preventReelsSpin: [],
            anticipatingReels: [],
            winningSymbols: [],
            tinting: []
        };
    }

    /** Sets up utilities for the machine, such as grid utilities used for positioning symbols. */
    protected override createUtils(): void
    {
        this.utils = {
            grid: new GridUtils(this.config),
        };
    }

    /**
     * Initializes and registers systems for the reel machine, including initialization,
     * idle, grid, and spin systems, which manage various aspects of the reel behavior.
     */
    protected override createSystems(): void
    {
        this.systems = {
            init: new InitSystem(this),
            idle: new IdleSystem(this),
            grid: new GridSystem(this),
            spin: new ReelsSpinSystem(this),
            layering: new LayeringSystem(this),
            resetWinningSymbols: new ResetWinningSymbolsSystem(this),
            allWinSymbols: new AllWinningSymbolSystem(this),
            allWinLinesSet: new SetAllWinLinesSystem(this),
            winLinesResetIncrement: new WinningLinesResetIncrementSystem(this),
            winLinesIncrementing: new WinningLinesIncrementSystem(this),
            setWinLineSymbols: new SetWinningLineSymbolsSystem(this),
            setWinLine: new SetCurrentWinLinesSystem(this),
            winLinesAnimations: new WinLinesAnimationsSystem(this),
            celebrateSymbols: new CelebrateSystem(this),
            winningSymbolsAnim: new WinningSymbolAnimationsSystem(this),
            tintWinningSymbolsAnim: new WinningSymbolTintingSystem(this),
            tinting: new TintingSymbolsSystem(this),
            resetTinting: new ResetTintSystem(this),
            displayTotalLinesWin: new DisplayTotalLinesWinSystem(this),
            displayLineWin: new DisplayLineWinValueSystem(this),
            interactive: new InteractiveGridSystem(this),
            blockExitState: new BlockExitStateSystem(this),
            masking: new MaskingSystem(this),
            blurSymbols: new BlurSymbolsSystem(this),
        };
    }

    /** Initializes the state machine for managing reel states and transitions. */
    protected createStateMachine(): void
    {
        this.stateMachine = new ClassicReelsStateMachine(this);
    }

    /**
     * Updates the reel machine and its state based on the delta time.
     * Processes inputs, updates the state machine, and triggers system updates.
     * @param {number} dt - Time delta in milliseconds since the last update.
     */
    override update(dt: number): void
    {
        this.stateMachine.handleInput(this);
        this.stateMachine.update(dt);
        super.update(dt);
    }

    /**
     * Creates and returns a new Symbol instance based on the provided key.
     * The symbol is retrieved from the machine's configuration.
     * @param {string} key - The unique key for the symbol configuration.
     * @returns {symbol} The newly created Symbol instance.
     */
    createSymbol(key: string): ValuableReelSymbol
    {
        return new ValuableReelSymbol(this.config.symbols[key]);
    }

    override destroy() {
        Object.values(this.systems).forEach((system) => {
            system.destroy()
        })
    }
}
