import { ActivityRunner } from '../activities';
import PauseClock from '../activities/PauseClock';
import ResumeClock from '../activities/ResumeClock';
import StopAllScenes from '../activities/StopAllScenes';
import SwitchToCasinoRounds from '../activities/SwitchToCasinoRounds';
import { ErrorProcessor } from '../errors/ErrorProcessor';

import type EventEmitter from 'eventemitter3';

type CasinoRoundsCapable = {
    enterCasinoRoundsMode: () => void;
    completeModeSwitching: () => void;
};

type BaseGameModel = EventEmitter & CasinoRoundsCapable;

/** Base controller wiring model events into activity-driven flows. */
export default class BaseGameController
{
    protected readonly activityRunner: ActivityRunner;

    protected readonly errorProcessor: ErrorProcessor;

    constructor(protected readonly model: BaseGameModel)
    {
        this.activityRunner = new ActivityRunner();
        this.errorProcessor = new ErrorProcessor(this.activityRunner);

        this.activityRunner.on('error', this.handleError, this);
        this.model.on('error', this.handleError, this);

        this.model.on('showBigWin', this.handleShowBigWin, this);
        this.model.on('showTotalWin', this.handleShowTotalWin, this);
        this.model.on('showMaxWin', this.handleShowMaxWin, this);

        this.model.on('respinsGameTriggered', this.handleRespinsGameTriggered, this);
        this.model.on('respinsGameRestore', this.handleRespinsGameRestore, this);
        this.model.on('exitRespinGame', this.handleExitRespinsGame, this);
        this.model.on('freespinsGameTriggered', this.handleFreespinsGameTriggered, this);
        this.model.on('freespinsGameRestore', this.handleFreespinsGameRestore, this);
        this.model.on('exitFreespinsGame', this.handleExitFreespinsGame, this);
        this.model.on('exitBonusGame', this.handleExitBonusGame, this);

        this.model.on('casinoRoundsTriggered', this.handleCasinoRoundsTriggered, this);
        this.model.on('casinoRoundsRestore', this.handleCasinoRoundsRestore, this);
        this.model.on('exitCasinoRounds', this.handleExitCasinoRounds, this);

        this.model.on('performBuyBonusButtonAction', this.handlePerformBuyBonusButtonAction, this);
        this.model.on('performPaytableAction', this.handlePerformPaytableAction, this);
        this.model.on('performRulesAction', this.handlePerformRulesAction, this);
        this.model.on('switchToCasinoRoundsMode', this.handleSwitchToCasinoRoundsMode, this);
    }

    /** Starts the game flow. Subclasses should enqueue bootstrap activities. */
    start(): void
    {
        /* override in subclass */
    }

    /** Hook for triggering a big-win presentation. */
    protected handleShowBigWin(): void
    {
        /* override in subclass */
    }

    /** Hook for showing the aggregated win screen. */
    protected handleShowTotalWin(): void
    {
        /* override in subclass */
    }

    /** Hook for highlighting a max win result. */
    protected handleShowMaxWin(): void
    {
        /* override in subclass */
    }

    /** Hook for when respins mode is triggered. */
    protected handleRespinsGameTriggered(): void
    {
        /* override in subclass */
    }

    /** Hook for restoring respins mode from persistence. */
    protected handleRespinsGameRestore(): void
    {
        /* override in subclass */
    }

    /** Hook for when free-spins mode is triggered. */
    protected handleFreespinsGameTriggered(): void
    {
        /* override in subclass */
    }

    /** Hook for restoring free-spins state. */
    protected handleFreespinsGameRestore(): void
    {
        /* override in subclass */
    }

    /** Hook for leaving respins mode. */
    protected handleExitRespinsGame(): void
    {
        /* override in subclass */
    }

    /** Hook for leaving free-spins mode. */
    protected handleExitFreespinsGame(): void
    {
        /* override in subclass */
    }

    /** Hook for leaving the bonus game flow. */
    protected handleExitBonusGame(): void
    {
        /* override in subclass */
    }

    /** Hook for starting casino rounds. */
    protected handleCasinoRoundsTriggered(): void
    {
        /* override in subclass */
    }

    /** Hook for restoring casino rounds mode. */
    protected handleCasinoRoundsRestore(): void
    {
        /* override in subclass */
    }

    /** Hook for leaving casino rounds mode. */
    protected handleExitCasinoRounds(): void
    {
        /* override in subclass */
    }

    /** Hook for when the buy-bonus button is pressed. */
    protected handlePerformBuyBonusButtonAction(): void
    {
        /* override in subclass */
    }

    /** Hook for when the paytable button is pressed. */
    protected handlePerformPaytableAction(): void
    {
        /* override in subclass */
    }

    /** Hook for when the rules button is pressed. */
    protected handlePerformRulesAction(): void
    {
        /* override in subclass */
    }

    /**
     * Handles unexpected failures by stopping the flow and showing popups.
     * @param error
     */
    protected handleError(error: unknown): void
    {
        console.log('Game controller handled an error event');
        this.activityRunner.clear();
        console.log('this.activityRunner.isError', this.activityRunner.isError);
        console.log(this.activityRunner.isRunning);
        this.activityRunner.addActivity(new PauseClock());
        this.errorProcessor.process(error);
        this.activityRunner.addActivity(new StopAllScenes());
        this.activityRunner.addActivity(new ResumeClock());
        this.restoreAfterError();
    }

    /** Enqueues the casino rounds transition activity. */
    protected handleSwitchToCasinoRoundsMode(): void
    {
        this.activityRunner.addActivity(new SwitchToCasinoRounds(this.model));
    }

    /** Hook for rebuilding UI after the error sequence finishes. */
    protected restoreAfterError(): void
    {
        /* override in subclass */
    }
}

export type { BaseGameModel };
