/*:
 * @plugindesc v2.4 高度なルート表示プラグイン（完全版・デバッグ強化版）
 * @author YourName
 * 
 * @param RouteColor
 * @text ルートの色
 * @desc ルートを表示する色（CSS形式）
 * @default #FF0000
 * 
 * @param RouteOpacity
 * @text ルートの不透明度
 * @desc ルートの不透明度（0-255）
 * @type number
 * @min 0
 * @max 255
 * @default 128
 * 
 * @param RouteThickness
 * @text ルートの太さ
 * @desc ルートの線の太さ（ピクセル）
 * @type number
 * @min 1
 * @default 4
 * 
 * @param DebugMode
 * @text デバッグモード
 * @desc デバッグ情報を表示するかどうか
 * @type boolean
 * @default true
 * 
 * @command showRoute
 * @text ルートを表示
 * @desc 指定した座標またはイベントIDまでのルートを表示します
 * 
 * @arg target
 * @type select
 * @option 座標
 * @value coordinates
 * @option イベントID
 * @value eventId
 * @default coordinates
 * @text 目標タイプ
 * @desc 座標またはイベントIDのどちらで目標を指定するか
 * 
 * @arg x
 * @type number
 * @text X座標
 * @desc 目的地のX座標（座標指定の場合）
 * 
 * @arg y
 * @type number
 * @text Y座標
 * @desc 目的地のY座標（座標指定の場合）
 * 
 * @arg eventId
 * @type number
 * @text イベントID
 * @desc 目的地のイベントID（イベントID指定の場合）
 * 
 * @command addWaypoint
 * @text 経由地点を追加
 * @desc ルートに経由地点を追加します
 * 
 * @arg x
 * @type number
 * @text X座標
 * @desc 経由地点のX座標
 * 
 * @arg y
 * @type number
 * @text Y座標
 * @desc 経由地点のY座標
 * 
 * @command clearRoute
 * @text ルートをクリア
 * @desc 表示中のルートをクリアします
 * 
 * @help 
 * このプラグインは高度なルート表示機能を提供します。
 * 複数の経由地点の設定、動的な障害物の更新、
 * ルートの表示スタイルのカスタマイズが可能です。
 * また、座標またはイベントIDを指定してルートを表示できます。
 * 
 * プラグインコマンド：
 * RouteDisplayPlugin showRoute target x y - 指定座標へのルートを表示
 * RouteDisplayPlugin showRoute target eventId - 指定イベントへのルートを表示
 * RouteDisplayPlugin addWaypoint x y - 経由地点を追加
 * RouteDisplayPlugin clearRoute - ルートをクリア
 */

(() => {
    const pluginName = "AdvancedRouteDisplayPlugin";
    const parameters = PluginManager.parameters(pluginName);

    const RouteColor = String(parameters['RouteColor'] || '#FF0000');
    const RouteOpacity = Number(parameters['RouteOpacity'] || 128);
    const RouteThickness = Number(parameters['RouteThickness'] || 4);
    const DebugMode = parameters['DebugMode'] === 'true';

    let currentRoute = [];
    let waypoints = [];
    let routeSprite = null;

    // デバッグログ関数
    function debugLog(...args) {
        if (DebugMode) {
            console.log('[RouteFinder]', ...args);
        }
    }

    // ノードクラス（A*アルゴリズム用）
    class Node {
        constructor(x, y, cost, heuristic) {
            this.x = x;
            this.y = y;
            this.cost = cost;
            this.heuristic = heuristic;
            this.totalCost = cost + heuristic;
            this.parent = null;
        }
    }

    // A*アルゴリズムの実装
    function aStar(start, goal, map) {
        debugLog('A* search started:', start, 'to', goal);
        const openList = [];
        const closedList = new Set();
        const startNode = new Node(start[0], start[1], 0, manhattanDistance(start, goal));
        openList.push(startNode);

        let iterations = 0;
        const maxIterations = 10000; // 無限ループ防止

        while (openList.length > 0 && iterations < maxIterations) {
            iterations++;
            openList.sort((a, b) => a.totalCost - b.totalCost);
            const currentNode = openList.shift();

            if (iterations % 10 === 0 || iterations < 100) {  // より頻繁にログを出力
                debugLog(`Iteration ${iterations}:`, 
                         `Current: (${currentNode.x}, ${currentNode.y})`,
                         `f: ${currentNode.totalCost}, g: ${currentNode.cost}, h: ${currentNode.heuristic}`,
                         `Open list size: ${openList.length}`,
                         `Closed list size: ${closedList.size}`);
            }

            if (currentNode.x === goal[0] && currentNode.y === goal[1]) {
                debugLog('Goal reached!');
                return reconstructPath(currentNode);
            }

            // ゴールがイベントの場合、隣接するタイルも検討
            if (map[goal[1]][goal[0]] === 1) {
                const adjacentToGoal = 
                    Math.abs(currentNode.x - goal[0]) <= 1 && 
                    Math.abs(currentNode.y - goal[1]) <= 1;
                if (adjacentToGoal) {
                    debugLog('Adjacent to impassable goal (event)');
                    return reconstructPath(currentNode);
                }
            }

            closedList.add(`${currentNode.x},${currentNode.y}`);

            const neighbors = getNeighbors(currentNode, map);

            for (const neighbor of neighbors) {
                if (closedList.has(`${neighbor.x},${neighbor.y}`)) continue;

                const tentativeCost = currentNode.cost + 1;
                const existingNode = openList.find(node => node.x === neighbor.x && node.y === neighbor.y);

                if (!existingNode || tentativeCost < existingNode.cost) {
                    neighbor.cost = tentativeCost;
                    neighbor.heuristic = manhattanDistance([neighbor.x, neighbor.y], goal);
                    neighbor.totalCost = neighbor.cost + neighbor.heuristic;
                    neighbor.parent = currentNode;

                    if (!existingNode) {
                        openList.push(neighbor);
                    }
                }
            }
        }

        debugLog('No path found or max iterations reached');
        return null; // パスが見つからない場合
    }

    // マンハッタン距離の計算
    function manhattanDistance(a, b) {
        return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
    }

    // 隣接ノードの取得
    function getNeighbors(node, map) {
        const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; // 斜め移動を除外
        const neighbors = [];

        for (const [dx, dy] of directions) {
            const x = node.x + dx;
            const y = node.y + dy;

            if (isValidPosition(x, y, map)) {
                neighbors.push(new Node(x, y, node.cost + 1, 0));
            }
        }

        return neighbors;
    }

    // 有効な位置かどうかのチェック
    function isValidPosition(x, y, map) {
        return x >= 0 && x < map[0].length && y >= 0 && y < map.length && map[y][x] === 0;
    }

    // パスの再構築
    function reconstructPath(node) {
        const path = [];
        while (node) {
            path.unshift([node.x, node.y]);
            node = node.parent;
        }
        return path;
    }

    // マップデータの解析
    function analyzeMap() {
        const width = $gameMap.width();
        const height = $gameMap.height();
        const result = new Array(height).fill(0).map(() => new Array(width).fill(0));

        debugLog('Analyzing map. Size:', width, 'x', height);

        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const passable = [2, 4, 6, 8].some(d => $gameMap.isPassable(x, y, d));
                result[y][x] = passable ? 0 : 1;
                debugLog(`Tile at (${x}, ${y}) is ${passable ? 'passable' : 'impassable'}`);
            }
        }

        // 動的な障害物（イベント）の処理
        $gameMap.events().forEach(event => {
            if (event && !event.through) {
                const [x, y] = [event._x, event._y];
                result[y][x] = 1;
                debugLog(`Event obstacle at (${x}, ${y}), Event ID: ${event.eventId()}`);
            }
        });

        debugLog('Map analysis complete. Passability map:');
        for (let y = 0; y < height; y++) {
            debugLog(result[y].join('').replace(/0/g, '.').replace(/1/g, '#'));
        }

        return result;
    }

    // ルートの表示
    function displayRoute(route) {
        debugLog('Displaying route:', route);
        if (routeSprite) {
            SceneManager._scene._spriteset._tilemap.removeChild(routeSprite);
        }

        const bitmap = new Bitmap($gameMap.width() * $gameMap.tileWidth(), $gameMap.height() * $gameMap.tileHeight());
        const context = bitmap.context;
        context.strokeStyle = RouteColor;
        context.lineWidth = RouteThickness;
        context.globalAlpha = RouteOpacity / 255;
        context.beginPath();

        route.forEach((point, index) => {
            const [x, y] = point;
            const screenX = x * $gameMap.tileWidth() + $gameMap.tileWidth() / 2;
            const screenY = y * $gameMap.tileHeight() + $gameMap.tileHeight() / 2;

            if (index === 0) {
                context.moveTo(screenX, screenY);
            } else {
                context.lineTo(screenX, screenY);
            }
        });

        context.stroke();

        routeSprite = new Sprite(bitmap);
        routeSprite.z = 9; // プレイヤーより上、イベントより下に表示
        SceneManager._scene._spriteset._tilemap.addChild(routeSprite);
        debugLog('Route sprite added to tilemap');
    }

    // プラグインコマンド
    PluginManager.registerCommand(pluginName, "showRoute", args => {
        const target = args.target;
        let goalX, goalY;

        debugLog('showRoute command called with args:', args);

        if (target === 'coordinates') {
            goalX = Number(args.x);
            goalY = Number(args.y);
            debugLog('Coordinates target:', goalX, goalY);
        } else if (target === 'eventId') {
            const eventId = Number(args.eventId);
            debugLog('EventId target:', eventId);
            const event = $gameMap.event(eventId);
            if (event) {
                goalX = event.x;
                goalY = event.y;
                debugLog('Event found. Position:', goalX, goalY);
            } else {
                console.error(`指定されたイベントID ${eventId} が見つかりません`);
                debugLog('All events:', $gameMap.events().map(e => `ID: ${e.eventId()}, Pos: (${e.x}, ${e.y})`));
                return;
            }
        } else {
            console.error('Invalid target type:', target);
            return;
        }

        const start = [$gamePlayer.x, $gamePlayer.y];
        const goal = [goalX, goalY];
        debugLog('Route calculation:', start, 'to', goal);

        const map = analyzeMap();
        debugLog('Map analysis complete. Size:', map.length, 'x', map[0].length);
        debugLog('Map passability:');
        for (let y = 0; y < map.length; y++) {
            debugLog(map[y].join('').replace(/0/g, '.').replace(/1/g, '#'));
        }

        // 簡単なケースのテスト
        const testStart = [start[0], start[1]];
        const testGoal = [Math.min(start[0] + 1, $gameMap.width() - 1), start[1]];
        debugLog('Testing simple route:', testStart, 'to', testGoal);
        const testRoute = aStar(testStart, testGoal, map);
        if (testRoute) {
            debugLog('Simple route test successful:', testRoute);
        } else {
            debugLog('Simple route test failed');
        }

        let fullRoute = [start];
        let currentStart = start;

        // 経由地点を含めたルートの計算
        for (const waypoint of waypoints) {
            const partialRoute = aStar(currentStart, waypoint, map);
            if (partialRoute) {
                fullRoute = fullRoute.concat(partialRoute.slice(1));
                currentStart = waypoint;
            } else {
                debugLog('Failed to find route to waypoint:', waypoint);
            }
        }

        const finalRoute = aStar(currentStart, goal, map);
        if (finalRoute) {
            fullRoute = fullRoute.concat(finalRoute.slice(1));
            currentRoute = fullRoute;
            debugLog('Full route found:', fullRoute);
            setTimeout(() => {
                displayRoute(fullRoute);
            }, 500);
        } else {
            console.error(`ルートが見つかりません。Start: (${currentStart[0]}, ${currentStart[1]}), Goal: (${goal[0]}, ${goal[1]})`);
            debugLog('Failed to find route. Map state around goal:');
            for (let y = Math.max(0, goal[1] - 2); y <= Math.min(map.length - 1, goal[1] + 2); y++) {
                let row = '';
                for (let x = Math.max(0, goal[0] - 2); x <= Math.min(map[0].length - 1, goal[0] + 2); x++) {
                    row += map[y][x] === 0 ? '.' : '#';
                }
                debugLog(row);
            }
        }
    });

    PluginManager.registerCommand(pluginName, "addWaypoint", args => {
        const x = Number(args.x);
        const y = Number(args.y);
        waypoints.push([x, y]);
        debugLog('Waypoint added:', x, y);
    });

    PluginManager.registerCommand(pluginName, "clearRoute", args => {
        if (routeSprite) {
            SceneManager._scene._spriteset._tilemap.removeChild(routeSprite);
            routeSprite = null;
        }
        currentRoute = [];
        waypoints = [];
        debugLog('Route and waypoints cleared');
    });

    // マップ更新時の処理
    const _Game_Map_update = Game_Map.prototype.update;
    Game_Map.prototype.update = function(sceneActive) {
        _Game_Map_update.call(this, sceneActive);
        if (currentRoute.length > 0) {
            const map = analyzeMap();
            const start = [$gamePlayer.x, $gamePlayer.y];
            const goal = currentRoute[currentRoute.length - 1];
            
            debugLog('Updating route:', start, 'to', goal);

            let fullRoute = [start];
            let currentStart = start;

            // 経由地点を含めたルートの再計算
            for (const waypoint of waypoints) {
                const partialRoute = aStar(currentStart, waypoint, map);
                if (partialRoute) {
                    fullRoute = fullRoute.concat(partialRoute.slice(1));
                    currentStart = waypoint;
                } else {
                    debugLog('Failed to update route to waypoint:', waypoint);
                }
            }

            const finalRoute = aStar(currentStart, goal, map);
            if (finalRoute) {
                fullRoute = fullRoute.concat(finalRoute.slice(1));
                currentRoute = fullRoute;
                displayRoute(fullRoute);
                debugLog('Route updated successfully');
            } else {
                console.error(`ルートの更新に失敗しました。Start: (${currentStart[0]}, ${currentStart[1]}), Goal: (${goal[0]}, ${goal[1]})`);
                debugLog('Failed to update route. Map state:', map);
            }
        }
    };

    // スプライトセットの更新後にルートスプライトを再描画
    const _Spriteset_Map_update = Spriteset_Map.prototype.update;
    Spriteset_Map.prototype.update = function() {
        _Spriteset_Map_update.call(this);
        if (currentRoute.length > 0 && routeSprite) {
            this._tilemap.addChild(routeSprite);
            debugLog('Route sprite re-added to tilemap');
        }
    };

    // デバッグ用の関数
    function debugDrawMap(map) {
        if (!DebugMode) return;

        const width = map[0].length;
        const height = map.length;
        const tileSize = 20;

        const canvas = document.createElement('canvas');
        canvas.width = width * tileSize;
        canvas.height = height * tileSize;
        canvas.style.position = 'absolute';
        canvas.style.top = '0';
        canvas.style.left = '0';
        canvas.style.zIndex = '9999';
        document.body.appendChild(canvas);

        const ctx = canvas.getContext('2d');

        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                ctx.fillStyle = map[y][x] === 0 ? 'rgba(0, 255, 0, 0.5)' : 'rgba(255, 0, 0, 0.5)';
                ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
                ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
                ctx.strokeRect(x * tileSize, y * tileSize, tileSize, tileSize);
            }
        }

        // プレイヤーの位置を青色で表示
        const playerX = $gamePlayer.x;
        const playerY = $gamePlayer.y;
        ctx.fillStyle = 'rgba(0, 0, 255, 0.7)';
        ctx.fillRect(playerX * tileSize, playerY * tileSize, tileSize, tileSize);

        debugLog('Debug map drawn');
    }

    // プラグイン初期化時にデバッグマップを描画
    const _Scene_Map_start = Scene_Map.prototype.start;
    Scene_Map.prototype.start = function() {
        _Scene_Map_start.call(this);
        if (DebugMode) {
            const map = analyzeMap();
            debugDrawMap(map);
        }
    };

    // マップ遷移時にデバッグマップを更新
    const _Game_Player_performTransfer = Game_Player.prototype.performTransfer;
    Game_Player.prototype.performTransfer = function() {
        _Game_Player_performTransfer.call(this);
        if (DebugMode) {
            // 少し遅延を入れてマップが完全に読み込まれるのを待つ
            setTimeout(() => {
                const map = analyzeMap();
                debugDrawMap(map);
            }, 500);
        }
    };

    // デバッグ情報をコンソールに出力
    function printDebugInfo() {
        if (!DebugMode) return;

        debugLog('Current player position:', $gamePlayer.x, $gamePlayer.y);
        debugLog('Current route:', currentRoute);
        debugLog('Waypoints:', waypoints);
        debugLog('Map passability:');
        const map = analyzeMap();
        for (let y = 0; y < map.length; y++) {
            let row = '';
            for (let x = 0; x < map[y].length; x++) {
                row += map[y][x] === 0 ? '.' : '#';
            }
            debugLog(row);
        }
    }

    // 定期的にデバッグ情報を更新
    if (DebugMode) {
        setInterval(printDebugInfo, 5000); // 5秒ごとに更新
    }

    // エラーハンドリング強化
    window.addEventListener('error', function(e) {
        console.error('AdvancedRouteDisplayPlugin Error:', e.message, 'at', e.filename, ':', e.lineno);
    });

    debugLog('AdvancedRouteDisplayPlugin initialized');
})();