/*:
 * @plugindesc 選択肢分岐同期機能付きランダム選択肢表示プラグイン
 * @author えむうん
 * @target MZ
 * 
 * @command setChoiceOptions
 * @text 選択肢オプション設定
 * @desc 選択肢のランダム化とコモンイベント起動を設定します。
 *
 * @arg choiceGroupId
 * @text 選択肢グループID
 * @type number
 * @min 1
 * @desc この選択肢群を識別するための一意のID
 * @default 1
 *
 * @arg randomCount
 * @text ランダム表示数
 * @type number
 * @min 0
 * @desc ランダムに表示する選択肢の数（0でランダム化無効、省略で全て表示）
 * @default 0
 *
 * @arg eventIds
 * @text コモンイベントID群
 * @type string
 * @desc カンマ区切りでコモンイベントIDを指定。例: 1,2,3,0,5 (0は無効)
 * @default 0
 * 
 * @help
 * このプラグインは、選択肢のランダム表示、コモンイベント即時実行、
 * および選択肢分岐の同期を行います。
 * 
 * 拡張機能：
 * - 選択肢グループIDによる個別管理
 * - 選択肢とイベントの同期的なランダム化
 * - 選択肢分岐処理の同期
 * - コモンイベントの同期実行
 * 
 * 使用方法：
 * 1. イベントエディタで通常通り選択肢を設定します。
 * 2. 選択肢の直前にプラグインコマンド「選択肢オプション設定」を配置します。
 * 3. 選択肢グループID、ランダム表示数、コモンイベントIDを設定します。
 * 4. 選択肢を表示するイベントコマンドを配置します。
 * 
 * 注意：
 * - 設定は選択肢グループIDに紐づけて保存されます。
 * - 選択肢の順序が変更されても、対応する分岐処理とイベントが正しく実行されます。
 */

(() => {
    const pluginName = "OptimizedRandomChoiceEventPlugin";

    // 選択肢グループごとの設定を保持するオブジェクト
    const choiceGroupSettings = new Map();

    // 現在アクティブな選択肢グループIDを保持
    let activeChoiceGroupId = null;

    // 選択肢と元のインデックスの対応を保持する配列
    let originalIndices = [];

    // プラグインコマンドの登録
    PluginManager.registerCommand(pluginName, "setChoiceOptions", args => {
        const groupId = Number(args.choiceGroupId);
        const settings = {
            randomCount: Number(args.randomCount) || 0,
            eventIds: args.eventIds.split(',').map(id => Number(id))
        };
        
        choiceGroupSettings.set(groupId, settings);
        activeChoiceGroupId = groupId;
        
        console.log(`選択肢グループ ${groupId} の設定を保存しました。`);
    });

    // Game_Message.prototype.setChoices の拡張
    const _Game_Message_prototype_setChoices = Game_Message.prototype.setChoices;
    Game_Message.prototype.setChoices = function(choices, defaultType, cancelType) {
        let finalChoices = choices;
        let finalEventIds = [];
        originalIndices = choices.map((_, index) => index);
        
        if (activeChoiceGroupId && choiceGroupSettings.has(activeChoiceGroupId)) {
            const settings = choiceGroupSettings.get(activeChoiceGroupId);
            finalEventIds = settings.eventIds;

            if (settings.randomCount > 0) {
                const shuffleResult = shuffleArrayWithIndices(
                    choices,
                    settings.eventIds,
                    originalIndices
                );
                
                finalChoices = shuffleResult.choices;
                finalEventIds = shuffleResult.eventIds;
                originalIndices = shuffleResult.indices;

                if (settings.randomCount < finalChoices.length) {
                    finalChoices = finalChoices.slice(0, settings.randomCount);
                    finalEventIds = finalEventIds.slice(0, settings.randomCount);
                    originalIndices = originalIndices.slice(0, settings.randomCount);
                }

                defaultType = defaultType < 0 ? defaultType : originalIndices.indexOf(defaultType);
                cancelType = cancelType < 0 ? cancelType : originalIndices.indexOf(cancelType);
            }
        }

        _Game_Message_prototype_setChoices.call(this, finalChoices, defaultType, cancelType);
        this._eventIds = finalEventIds;
        this._originalIndices = originalIndices;
        this._choiceGroupId = activeChoiceGroupId;

        // アクティブなグループIDをリセット
        activeChoiceGroupId = null;
    };

    // Window_ChoiceList.prototype.select の拡張
    const _Window_ChoiceList_select = Window_ChoiceList.prototype.select;
    Window_ChoiceList.prototype.select = function(index) {
        const previousIndex = this.index();
        _Window_ChoiceList_select.call(this, index);
        
        if (this.isOpen() && index !== previousIndex && index >= 0 && index < this._list.length) {
            const eventId = $gameMessage._eventIds[index];
            if (eventId > 0) {
                this.triggerCommonEvent(eventId);
            }
        }
    };

    // 選択肢の結果を取得する処理の拡張
    const _Game_Message_prototype_onChoice = Game_Message.prototype.onChoice;
    Game_Message.prototype.onChoice = function(n) {
        // 元の選択肢番号を取得
        const originalIndex = this._originalIndices ? this._originalIndices[n] : n;
        // 元の選択肢番号で分岐処理を実行
        _Game_Message_prototype_onChoice.call(this, originalIndex);
    };

    // Game_Interpreter.prototype.setupChoices の拡張
    const _Game_Interpreter_prototype_setupChoices = Game_Interpreter.prototype.setupChoices;
    Game_Interpreter.prototype.setupChoices = function(params) {
        _Game_Interpreter_prototype_setupChoices.call(this, params);
        // 選択肢の結果を保存する変数に元のインデックスが設定されるように
        this._branch[this._indent] = params[0];
    };

    // コモンイベント実行機能
    Window_ChoiceList.prototype.triggerCommonEvent = function(eventId) {
        const commonEvent = $dataCommonEvents[eventId];
        if (commonEvent) {
            const interpreter = new Game_Interpreter();
            interpreter.setup(commonEvent.list, 0);
            interpreter.update();
        }
    };

    // 配列のシャッフル機能（インデックスも同期）
    function shuffleArrayWithIndices(array, eventIds, indices) {
        const length = array.length;
        const shuffled = array.slice();
        const shuffledEvents = eventIds.slice();
        const shuffledIndices = indices.slice();
        
        for (let i = length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
            [shuffledEvents[i], shuffledEvents[j]] = [shuffledEvents[j], shuffledEvents[i]];
            [shuffledIndices[i], shuffledIndices[j]] = [shuffledIndices[j], shuffledIndices[i]];
        }
        
        return {
            choices: shuffled,
            eventIds: shuffledEvents,
            indices: shuffledIndices
        };
    }

    // イベント終了時にクリーンアップ
    const _Game_Interpreter_terminate = Game_Interpreter.prototype.terminate;
    Game_Interpreter.prototype.terminate = function() {
        _Game_Interpreter_terminate.call(this);
        if (this._depth === 0) {
            choiceGroupSettings.clear();
            activeChoiceGroupId = null;
            originalIndices = [];
        }
    };
})();