import StaticSymbol from '../entities/StaticSymbol';
import BasicStateMachine from '../states/BasicStateMachine';
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 StaticReelsSpinSystem from '../systems/StaticReelsSpinSystem';
import GridUtils from '../utils/GridUtils';
import BaseMachine from './BaseMachine';

/**
 * @class StaticReelsMachine
 * @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 StaticReelsMachine extends BaseMachine
{
    public stateMachine: BasicStateMachine;

    /**
     * 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
        };
    }

    /** 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
        };
    }

    /** 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: []
        };
    }

    /** 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 StaticReelsSpinSystem(this),
            layering: new LayeringSystem(this),
            interactive: new InteractiveGridSystem(this),
        };
    }

    /** Initializes the state machine for managing reel states and transitions. */
    protected createStateMachine(): void
    {
        this.stateMachine = new BasicStateMachine(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): StaticSymbol
    {
        return new StaticSymbol(this.config.symbols[key]);
    }
}
