/*:
 * @target MZ
 * @plugindesc NUUN_SceneFormation拡張プラグイン
 * @author 開発中
 * @base NUUN_SceneFormation
 * @orderAfter NUUN_SceneFormation
 * 
 * @help
 * このプラグインは、NUUN_SceneFormationプラグインを拡張し、
 * 以下の機能を追加します：
 * 
 * 1. アクターID001のキャラクターは常にパーティの先頭に固定され、
 *    並べ替えできません。
 * 2. アクターをメインメンバーに入れる際、そのアクターのメモ欄に記述した
 *    必要MP分をアクターID001の最大MPから減算します。
 * 3. アクターを控えメンバーに入れる際、そのアクターのメモ欄に記述した
 *    必要MP分をアクターID001の最大MPに加算します。
 * 4. アクターID001の最大MPが足りない場合、メインメンバーに入れることができません。
 * 5. 必要最大MPが足りないキャラクターのグラフィックは少し暗くなります。
 * 6. キャラクターグラフィックの上に、メモ欄で記述した必要MP値を表示します。
 * 7. 同じメンバーリスト内での移動は、必要MP値に関係なく可能です。
 * 
 * アクターのメモ欄:
 * <requiredMP:X>  Xは必要MPの値
 * 
 * @param DarkenOpacity
 * @text 暗くする不透明度
 * @type number
 * @min 0
 * @max 255
 * @default 128
 * @desc MPが足りないキャラクターを暗くする際の不透明度
 */

(function() {
    'use strict';
    const pluginName = "NUUN_SceneFormation_Extension";
    const parameters = PluginManager.parameters(pluginName);
    const DarkenOpacity = Number(parameters['DarkenOpacity'] || 128);

    function logFormationChange(message) {
        console.log('[Formation Change] ' + message);
    }

    class FormationManager {
        constructor() {
            this._selectedIndex = -1;
            this._targetIndex = -1;
            this._isBattleMember = false;
        }

        setSelected(index, isBattleMember) {
            this._selectedIndex = index;
            this._isBattleMember = isBattleMember;
            logFormationChange(`Selected: Index ${index}, IsBattleMember: ${isBattleMember}`);
        }

        setTarget(index) {
            this._targetIndex = index;
            logFormationChange(`Target set: Index ${index}`);
        }

        isValidMove() {
            if (this._selectedIndex === -1 || this._targetIndex === -1) return false;
            if (this._selectedIndex === this._targetIndex) return false;
            if (this._selectedIndex === 0 && this._isBattleMember) return false; // ID001のキャラクターは動かせない
            return true;
        }

        executeMoveandAdjustMP() {
            if (!this.isValidMove()) {
                logFormationChange("Invalid move");
                return false;
            }

            const fromActor = this.getActor(this._selectedIndex, this._isBattleMember);
            const toActor = this.getActor(this._targetIndex, !this._isBattleMember);

            logFormationChange(`Executing move: From ${this._selectedIndex} to ${this._targetIndex}`);

            // アクターの移動を実行
            if (!$gameParty.swapOrderSafe(this._selectedIndex, this._targetIndex)) {
                logFormationChange("Failed to swap actors");
                return false;
            }

            // MP調整が必要な場合のみ実行
            if (this._isBattleMember !== (this._targetIndex < $gameParty.maxBattleMembers())) {
                if (!this.adjustMP(fromActor, toActor)) {
                    // MP調整に失敗した場合は元に戻す
                    $gameParty.swapOrderSafe(this._targetIndex, this._selectedIndex);
                    return false;
                }
            }

            return true;
        }

        adjustMP(fromActor, toActor) {
            let mpChange = 0;
            if (fromActor && this._isBattleMember) {
                mpChange += fromActor.requiredMP();
            }
            if (toActor && !this._isBattleMember) {
                mpChange -= toActor.requiredMP();
            }
            
            const leader = $gameParty.leader();
            if (leader && leader.mmp + mpChange >= 0) {
                $gameParty.modifyLeaderMmp(mpChange);
                logFormationChange(`MP adjusted: ${mpChange}`);
                return true;
            } else {
                logFormationChange("Not enough MP for adjustment");
                return false;
            }
        }

        getActor(index, isBattleMember) {
            if (isBattleMember) {
                return $gameParty.battleMembers()[index];
            } else {
                return $gameParty.allMembers()[index];
            }
        }
    }

    // グローバルなFormationManagerインスタンスを作成
    const formationManager = new FormationManager();

    const _Game_Actor_setup = Game_Actor.prototype.setup;
    Game_Actor.prototype.setup = function(actorId) {
        _Game_Actor_setup.call(this, actorId);
        this._originalMmp = this.mmp;
    };

    Game_Actor.prototype.requiredMP = function() {
        const match = /<requiredMP:(\d+)>/.exec(this.actor().note);
        return match ? parseInt(match[1]) : 0;
    };

    Game_Actor.prototype.canJoinBattle = function() {
        const leader = $gameParty.leader();
        return leader && leader.mmp >= this.requiredMP();
    };

    Game_Party.prototype.modifyLeaderMmp = function(value) {
        const leader = this.leader();
        if (leader) {
            const oldMmp = leader.mmp;
            const newMmp = oldMmp + value;
            leader.setMmp(newMmp);
            logFormationChange(`Leader MMP changed: ${oldMmp} -> ${newMmp} (${value > 0 ? '+' : ''}${value})`);
        }
    };

    Game_Actor.prototype.setMmp = function(value) {
        const paramId = 1; // MPのパラメータID
        const oldValue = this.param(paramId);
        this.addParam(paramId, value - oldValue);
    };

    // 安全なswapOrderメソッドを追加
    Game_Party.prototype.swapOrderSafe = function(index1, index2) {
        if (index1 === index2) {
            return true;
        }
        const maxBattleMembers = this.maxBattleMembers();
        const allMembers = this.allMembers();
        if (index1 >= allMembers.length || index2 >= allMembers.length) {
            return false;
        }
        const temp = allMembers[index1];
        allMembers[index1] = allMembers[index2];
        allMembers[index2] = temp;
        this._actors = allMembers.filter(actor => actor).map(actor => actor.actorId());
        $gamePlayer.refresh();
        return true;
    };

    const _Window_FormationBattleMember_processOk = Window_FormationBattleMember.prototype.processOk;
    Window_FormationBattleMember.prototype.processOk = function() {
        if (this._formation.getPendingIndex() >= 0) {
            formationManager.setTarget(this.index());
            if (formationManager.executeMoveandAdjustMP()) {
                _Window_FormationBattleMember_processOk.call(this);
            } else {
                SoundManager.playBuzzer();
            }
        } else {
            formationManager.setSelected(this.index(), true);
            _Window_FormationBattleMember_processOk.call(this);
        }
    };

    const _Window_FormationMember_processOk = Window_FormationMember.prototype.processOk;
    Window_FormationMember.prototype.processOk = function() {
        if (this._formation.getPendingIndex() >= 0) {
            formationManager.setTarget(this.index() + $gameParty.maxBattleMembers());
            if (formationManager.executeMoveandAdjustMP()) {
                _Window_FormationMember_processOk.call(this);
            } else {
                SoundManager.playBuzzer();
            }
        } else {
            formationManager.setSelected(this.index() + $gameParty.maxBattleMembers(), false);
            _Window_FormationMember_processOk.call(this);
        }
    };

    const _Window_FormationBattleMember_drawItem = Window_FormationBattleMember.prototype.drawItem;
    Window_FormationBattleMember.prototype.drawItem = function(index) {
        _Window_FormationBattleMember_drawItem.call(this, index);
        const actor = this.actor(index);
        if (actor) {
            this.drawRequiredMP(actor, this.itemRect(index));
        }
    };

    Window_FormationBattleMember.prototype.drawRequiredMP = function(actor, rect) {
        const requiredMP = actor.requiredMP();
        this.drawText(requiredMP, rect.x, rect.y, rect.width, 'right');
    };

    const _Window_FormationBattleMember_drawItemImage = Window_FormationBattleMember.prototype.drawItemImage;
    Window_FormationBattleMember.prototype.drawItemImage = function(actor, rect) {
        if (actor && !actor.canJoinBattle()) {
            this.contents.paintOpacity = DarkenOpacity;
        }
        _Window_FormationBattleMember_drawItemImage.call(this, actor, rect);
        this.contents.paintOpacity = 255;
    };

    const _Window_FormationMember_drawItem = Window_FormationMember.prototype.drawItem;
    Window_FormationMember.prototype.drawItem = function(index) {
        _Window_FormationMember_drawItem.call(this, index);
        const actor = this.actor(index);
        if (actor) {
            this.drawRequiredMP(actor, this.itemRect(index));
        }
    };

    Window_FormationMember.prototype.drawRequiredMP = function(actor, rect) {
        const requiredMP = actor.requiredMP();
        this.drawText(requiredMP, rect.x, rect.y, rect.width, 'right');
    };

    const _Window_FormationMember_drawItemImage = Window_FormationMember.prototype.drawItemImage;
    Window_FormationMember.prototype.drawItemImage = function(actor, rect) {
        if (actor && !actor.canJoinBattle()) {
            this.contents.paintOpacity = DarkenOpacity;
        }
        _Window_FormationMember_drawItemImage.call(this, actor, rect);
        this.contents.paintOpacity = 255;
    };

    const _Window_FormationBattleMember_isCurrentItemEnabled = Window_FormationBattleMember.prototype.isCurrentItemEnabled;
    Window_FormationBattleMember.prototype.isCurrentItemEnabled = function() {
        if (this.index() === 0) {
            return false;
        }
        const pendingIndex = this._formation.getPendingIndex();
        const isSameWindow = pendingIndex < 0 || pendingIndex < $gameParty.maxBattleMembers();
        if (isSameWindow) {
            return true;
        }
        return _Window_FormationBattleMember_isCurrentItemEnabled.call(this);
    };

    const _Window_FormationMember_isCurrentItemEnabled = Window_FormationMember.prototype.isCurrentItemEnabled;
    Window_FormationMember.prototype.isCurrentItemEnabled = function() {
        const pendingIndex = this._formation.getPendingIndex();
        const isSameWindow = pendingIndex < 0 || pendingIndex >= $gameParty.maxBattleMembers();
        if (isSameWindow) {
            return true;
        }
        const actor = this.actor(this.index());
        if (actor && !actor.canJoinBattle()) {
            return false;
        }
        return _Window_FormationMember_isCurrentItemEnabled.call(this);
    };

})();