import { StorageMgr, globalStorageMgr } from '../common/StorageMgr';
import { STORAGE_KEY } from '../common/Constants';

/**
 * UIFlowMgr — scene-flow state machine (task 9.2, req 12.7-12.8, 13.1).
 *
 * It does **not** perform `director.loadScene()` itself; the Cocos view layer
 * subscribes to `onSceneEnter` and performs the actual scene swap. Keeping
 * the flow engine-agnostic makes it trivial to Jest-test every boot path,
 * every settlement path, and the new story-intro gate (req 19.x).
 *
 * Decision D-4 / req 13.1 guardrail:
 *   The `showDifficultyPicker()` action simply does not exist; and
 *   `availableSettingsEntries()` purposefully omits it. A future contributor
 *   who tries to add a "difficulty" key will hit a TypeScript compile-error
 *   because the union `SettingsKey` is exhaustive.
 */

export type SceneId =
    | 'boot'
    | 'story_intro'
    | 'main_menu'
    | 'level_select'
    | 'gameplay'
    | 'settlement'
    | 'settings';

export type SettingsKey =
    | 'audio_volume'
    | 'layout_customisation'
    | 'replay_tutorial'
    | 'replay_story_intro';

export interface ISceneEnter {
    scene: SceneId;
    /** Optional payload (e.g. `{ levelId: '1-1' }` for gameplay). */
    payload?: Record<string, unknown>;
}

export interface IUIFlowCallbacks {
    onSceneEnter?: (ev: ISceneEnter) => void;
}

export class UIFlowMgr {
    private current: SceneId = 'boot';

    constructor(
        private readonly storage: StorageMgr = globalStorageMgr,
        private readonly callbacks: IUIFlowCallbacks = {}
    ) {}

    public get currentScene(): SceneId {
        return this.current;
    }

    /** Invoked by `GameBoot.start()` once engine is ready. */
    public onBoot(): void {
        if (this.storage.get<boolean>(STORAGE_KEY.StoryIntroSeen, false)) {
            this.enter('main_menu');
        } else {
            this.enter('story_intro');
        }
    }

    /** Called by StorySceneCtrl.onFinished(). */
    public onStoryFinished(): void {
        this.enter('gameplay', { levelId: '1-1' });
    }

    /** Main menu → level select. */
    public onPressStartGame(): void {
        // First-time "Start Game" may jump through the story again if we
        // ever reset; otherwise go to level select.
        if (!this.storage.get<boolean>(STORAGE_KEY.StoryIntroSeen, false)) {
            this.enter('story_intro');
        } else {
            this.enter('level_select');
        }
    }

    public onPickLevel(levelId: string): void {
        this.enter('gameplay', { levelId });
    }

    public onOpenSettings(): void {
        this.enter('settings');
    }

    public onCloseSettings(): void {
        this.enter('main_menu');
    }

    public onLevelCleared(nextLevelId: string | null): void {
        if (nextLevelId) {
            this.enter('settlement', { nextLevelId });
        } else {
            // After final boss settlement, back to the main menu.
            this.enter('settlement', { isChapterEnd: true });
        }
    }

    public onSettlementContinue(nextLevelId?: string): void {
        if (nextLevelId) this.enter('gameplay', { levelId: nextLevelId });
        else this.enter('main_menu');
    }

    public onPlayerDied(currentLevelId: string): void {
        this.enter('settlement', { levelId: currentLevelId, dead: true });
    }

    /**
     * Exhaustive list of settings entries available in the Settings scene.
     * Purposefully omits any difficulty-selection entry (req 13.1).
     */
    public availableSettingsEntries(): ReadonlyArray<SettingsKey> {
        return ['audio_volume', 'layout_customisation', 'replay_tutorial', 'replay_story_intro'];
    }

    // -----------------------------------------------------------------

    private enter(scene: SceneId, payload?: Record<string, unknown>): void {
        this.current = scene;
        this.callbacks.onSceneEnter?.({ scene, payload });
    }
}
