import { world, system, GameMode, ItemStack } from "@minecraft/server";
import { MapGenerator } from "./MapGenerator.js";
import { PhaseManager } from "./PhaseManager.js";
import { Config } from "../config.js";

export class GameManager {
    constructor(oneBlockSystem, inventoryMgr, economy) {
        this.oneBlockSystem = oneBlockSystem;
        this.inventoryMgr = inventoryMgr;
        this.economy = economy;
        this.mapGenerator = new MapGenerator(oneBlockSystem);
        this.phaseManager = new PhaseManager(this, oneBlockSystem);
        this.oneBlockSystem.phaseManager = this.phaseManager;

        this.gameState = "LOBBY";
        this.gameLoopInterval = null;
        this.lobbyLoopInterval = null; // ロビー用の保護ループ
        this.victoryInterval = null;
        this.tickCount = 0; 
        this.gameMode = "normal";

        this.lastHitMap = new Map();
        this.killCounts = new Map();

        this.lastSurvivorStr = null;
        this.lastDeadStr = null;

        // 初期化時にロビーループを開始
        this.startLobbyLoop();
    }

    /**
     * ロビー状態での監視ループ（落下保護など）
     */
    startLobbyLoop() {
        if (this.lobbyLoopInterval) system.clearRun(this.lobbyLoopInterval);
        this.lobbyLoopInterval = system.runInterval(() => {
            if (this.gameState !== "LOBBY") return;

            for (const player of world.getAllPlayers()) {
                // ロビーでの落下保護: Y < -80 (奈落) なら救出
                // ロビー自体が Y=-63 なので、0以下ではなく奈落まで落ちた場合のみ救出する
                if (player.location.y < -80) {
                    try {
                        // ロビー座標へ戻す
                        player.teleport({ x: 0, y: -63, z: 0 });
                        player.runCommand("effect @s resistance 5 255 true"); // 落下ダメージ防止
                    } catch(e) {}
                }
            }
        }, 10); // 0.5秒ごとにチェック
    }

    recordHit(victim, attacker) {
        if (!victim || !attacker) return;
        this.lastHitMap.set(victim.id, { 
            attackerId: attacker.id, 
            attackerName: attacker.name, 
            tick: this.tickCount 
        });
    }

    startGame(mode = "normal") {
        if (this.gameState !== "LOBBY") {
            world.sendMessage("§cGame is already running.");
            return;
        }

        // ゲーム開始時はロビーループを停止
        if (this.lobbyLoopInterval) system.clearRun(this.lobbyLoopInterval);

        this.gameMode = mode;
        this.gameState = "STARTING";
        this.tickCount = 0;
        this.lastHitMap.clear(); 
        this.killCounts.clear(); 

        const modeTitle = (mode === "blitz") ? "§c§lBLITZ MODE" : "§rNormal Mode";

        world.sendMessage("§b==================================");
        world.sendMessage("§l§e ONE BLOCK WARS §r");
        world.sendMessage(modeTitle);
        world.sendMessage("§b==================================");

        if (mode === "blitz") {
            world.sendMessage("§e[Blitz] §fPhase times are §c1/5§f. Resource drops are §ax5§f!");
        }

        const players = world.getAllPlayers();
        const playerCount = players.length;

        if (playerCount === 0) {
            world.sendMessage("§cNo players found!");
            this.gameState = "LOBBY";
            this.startLobbyLoop(); // 失敗したのでロビーループ再開
            return;
        }

        this.mapGenerator.resetMap();
        this.mapGenerator.generateMap(playerCount);

        system.runTimeout(() => {
            this.teleportPlayersToIslands(players);
            this.gameState = "INGAME";
            
            this.phaseManager.startGame(this.gameMode);

            for (const p of players) {
                this.resetPlayerTags(p);

                p.runCommand("gamemode survival");
                p.runCommand("clear");
                
                if (this.inventoryMgr) this.inventoryMgr.giveShopItem(p);

                p.runCommand("effect @s saturation 10000 255 true");
                p.runCommand("effect @s instant_health 1 255 true");
                
                p.addTag("obw_participant");
                p.removeTag("obw_eliminated");
            }

            this.startGameLoop();

        }, 40);
    }

    startGameLoop() {
        if (this.gameLoopInterval) system.clearRun(this.gameLoopInterval);
        this.gameLoopInterval = system.runInterval(() => {
            this.onTick();
        }, 1); 
    }

    onTick() {
        if (this.gameState !== "INGAME") return;
        
        this.tickCount++;
        this.phaseManager.onTick(this.tickCount);

        this.checkVoidFall();
        this.checkWinCondition();
        
        if (this.tickCount % 20 === 0) {
            this.checkLateJoiners();
            this.removeNetherPortals(); 
            this.updateStatsScoreboard(); 
        }
    }

    updateStatsScoreboard() {
        if (!this.economy) return;
        const allPlayers = world.getAllPlayers();
        const participants = allPlayers.filter(p => p.hasTag("obw_participant"));
        const survivors = participants.filter(p => !p.hasTag("obw_eliminated"));
        
        const currentSurvivorStr = `§bSurvivors: §f${survivors.length}`;
        const currentDeadStr = `§7Dead: §f${participants.length - survivors.length}`;

        if (this.lastSurvivorStr !== currentSurvivorStr) {
            if (this.lastSurvivorStr) this.economy.resetFakeScore(this.lastSurvivorStr);
            this.economy.setFakeScore(currentSurvivorStr, -1);
            this.lastSurvivorStr = currentSurvivorStr;
        }

        if (this.lastDeadStr !== currentDeadStr) {
            if (this.lastDeadStr) this.economy.resetFakeScore(this.lastDeadStr);
            this.economy.setFakeScore(currentDeadStr, -2);
            this.lastDeadStr = currentDeadStr;
        }
    }

    removeNetherPortals() {
        for (const player of world.getAllPlayers()) {
            if (player.dimension.id !== "minecraft:overworld") continue;
            try {
                player.runCommand("fill ~-4 ~-2 ~-4 ~4 ~2 ~4 air replace portal");
            } catch(e) {}
        }
    }

    checkLateJoiners() {
        for (const player of world.getAllPlayers()) {
            if (!player.hasTag("obw_participant") && !player.hasTag("obw_spectator_processed")) {
                if (player.getGameMode() === "spectator") {
                    try { player.addTag("obw_spectator_processed"); } catch(e) {}
                    continue;
                }

                try {
                    player.runCommand("gamemode spectator @s");
                    player.addTag("obw_spectator_processed");
                    player.sendMessage("§cGame in progress. You are now spectating.");
                    player.sendMessage("§7Wait for the next game to start.");
                } catch (e) {}
            }
        }
    }

    checkVoidFall() {
        const currentPhase = this.phaseManager.currentPhase;
        
        for (const player of world.getAllPlayers()) {
            if (player.location.y <= 0) {
                if (player.hasTag("obw_eliminated") || player.hasTag("obw_spectator_processed")) {
                    try {
                        player.teleport({ x: 0, y: 90, z: 0 });
                    } catch(e) {}
                    continue; 
                }

                if (!player.hasTag("obw_participant")) {
                    continue;
                }
                
                const health = player.getComponent("minecraft:health");
                if (health && health.currentValue <= 0) {
                    continue; 
                }

                this.handleVoidFall(player, currentPhase);
            }
        }
    }

    handleVoidFall(player, currentPhase) {
        const lastHit = this.lastHitMap.get(player.id);
        let killer = null;
        let killerName = null;

        if (lastHit && (this.tickCount - lastHit.tick) <= 200) {
            const allPlayers = world.getAllPlayers();
            killer = allPlayers.find(p => p.id === lastHit.attackerId);
            
            if (!killer && lastHit.attackerName) {
                killer = allPlayers.find(p => p.name === lastHit.attackerName);
            }
            killerName = lastHit.attackerName;
        }

        try {
            const cmd = `execute at "${player.name}" run kill @e[type=ender_pearl,r=100]`;
            player.dimension.runCommand(cmd);
        } catch(e) {}

        try {
            player.teleport({ x: player.location.x, y: -70, z: player.location.z });
        } catch(e) {}

        if (killer) {
            world.sendMessage(`§c${player.name} was knocked into the void by ${killer.name}!`);
            this.handlePvpKill(killer, player);
        } else if (killerName) {
            world.sendMessage(`§c${player.name} was knocked into the void by ${killerName} (Offline)!`);
        } else {
            world.sendMessage(`§c${player.name} fell into the void.`);
        }

        if (currentPhase >= 3) {
            this.eliminatePlayer(player);
            try { player.runCommand("gamemode spectator @s"); } catch(e) {}
        } else {
            if (currentPhase >= 2 && !player.hasTag("obw_eliminated")) {
                this.handleDeathLoss(player);
            }

            try { 
                const health = player.getComponent("minecraft:health");
                if (health) {
                    health.setCurrentValue(0);
                }
            } catch(e) {
                try { 
                    player.applyDamage(2000, { cause: "void" }); 
                } catch(e2) {}
            }
        }
    }

    onPlayerRespawn(player) {
        // 【修正】ロビー状態でのリスポーン処理
        // ロビー（Y=-63）へ戻す
        if (this.gameState === "LOBBY") {
            try {
                player.teleport({ x: 0, y: -63, z: 0 });
            } catch(e) {}
            return;
        }

        if (this.gameState !== "INGAME") return;
        if (player.hasTag("obw_eliminated")) return; 

        if (this.inventoryMgr) this.inventoryMgr.giveShopItem(player);
        
        system.runTimeout(() => {
            this.reapplyPassiveEffects(player);
        }, 20);
    }

    reapplyPassiveEffects(player) {
        try {
            if (player.hasTag("obw_upgrade_haste")) player.runCommand("effect @s haste 100000 1 true");
            if (player.hasTag("obw_upgrade_absorption")) player.runCommand("effect @s absorption 100000 0 true");
            if (player.hasTag("obw_upgrade_jump_boost")) player.runCommand("effect @s jump_boost 100000 0 true");
            if (player.hasTag("obw_upgrade_speed")) player.runCommand("effect @s speed 100000 0 true");
        } catch(e) {}
    }

    onPlayerDeath(player, damageSource) {
        if (this.gameState !== "INGAME") return;

        try {
            player.dimension.runCommand(`execute at "${player.name}" run kill @e[type=ender_pearl,r=100]`);
        } catch(e) {}
        
        if (damageSource && damageSource.damagingEntity && damageSource.damagingEntity.typeId === "minecraft:player") {
            const killer = damageSource.damagingEntity;
            this.handlePvpKill(killer, player);
        }

        const currentPhase = this.phaseManager.currentPhase;

        if (currentPhase >= 2 && !player.hasTag("obw_eliminated")) {
            this.handleDeathLoss(player);
        }

        if (currentPhase <= 2) return;

        this.eliminatePlayer(player);
    }

    handlePvpKill(killer, victim) {
        try {
            if (killer && killer.id && killer !== victim && killer.id !== victim.id) {
                const currentKills = this.killCounts.get(killer.id) || 0;
                this.killCounts.set(killer.id, currentKills + 1);
            }
        } catch(e) {}

        if (!this.economy) return;
        
        try {
            if (killer === victim) return;
            if (killer.id === victim.id) return;
        } catch(e) {}

        const victimMoney = this.economy.getMoney(victim);
        const stealAmount = Math.floor(victimMoney / 2);

        if (stealAmount > 0) {
            this.economy.subtractMoney(victim, stealAmount);
            if (killer) {
                this.economy.addMoney(killer, stealAmount);
                try {
                    killer.sendMessage(`§aYou stole §6$${stealAmount} §afrom ${victim.name}!`);
                    killer.playSound("random.levelup");
                } catch(e) {}
            }
            victim.sendMessage(`§c${killer ? killer.name : "Enemy"} stole §6$${stealAmount} §cfrom you!`);
        }
    }

    getPlayerKills(player) {
        return this.killCounts.get(player.id) || 0;
    }

    eliminatePlayer(player) {
        if (player.hasTag("obw_eliminated")) return;

        world.sendMessage(`§c${player.name} has been eliminated!`);
        try { player.addTag("obw_eliminated"); } catch (e) {}
        
        try {
            if (player.onScreenDisplay) {
                player.onScreenDisplay.setTitle("§cELIMINATED");
                player.onScreenDisplay.setSubtitle("§7You are now a spectator.");
            }
        } catch(e) {}
        
        try { player.runCommand(`gamemode spectator @s`); } catch (e) {}
        
        this.updateStatsScoreboard();
    }

    handleDeathLoss(player) {
        const inv = player.getComponent("inventory").container;
        const dim = player.dimension;
        const loc = player.location;

        for (let i = 0; i < inv.size; i++) {
            const item = inv.getItem(i);
            if (item) {
                if (!(item.typeId === "minecraft:emerald" && item.nameTag === "§aShop Menu")) {
                    if (loc.y > -60) {
                        try { dim.spawnItem(item, loc); } catch(e) {}
                    }
                }
                inv.setItem(i, undefined);
            }
        }
    }

    checkWinCondition() {
        if (this.gameState !== "INGAME") return;

        const allPlayers = world.getAllPlayers();
        const participants = allPlayers.filter(p => p.hasTag("obw_participant"));
        const survivors = participants.filter(p => !p.hasTag("obw_eliminated"));

        if (participants.length > 1) {
            if (survivors.length <= 1) {
                this.endGame(survivors.length === 1 ? survivors[0] : null);
            }
        } 
        else if (participants.length === 1) {
            if (survivors.length === 0) {
                this.endGame(null);
            }
        }
    }

    endGame(winner) {
        this.gameState = "ENDING";
        if (this.gameLoopInterval) system.clearRun(this.gameLoopInterval);
        this.phaseManager.stopGame();

        if (winner) {
            if (this.economy) this.economy.addMoney(winner, 1000);
            
            world.sendMessage(`§6§lVICTORY! §r§a${winner.name} wins the game!`);
            
            for (const p of world.getAllPlayers()) {
                try {
                    if (p === winner) {
                        p.onScreenDisplay.setTitle("§6§lVICTORY!");
                        p.onScreenDisplay.setSubtitle(`§eYou are the Champion!`);
                        p.playSound("random.levelup");
                    } else {
                        p.onScreenDisplay.setTitle("§c§lGAME OVER");
                        p.onScreenDisplay.setSubtitle(`§7Winner: §e${winner.name}`);
                    }
                } catch(e) {}
            }

            if (this.startVictoryCelebration) {
                this.startVictoryCelebration(winner);
            } else {
                console.warn("[GameManager] startVictoryCelebration method missing! Skipping animation.");
            }

        } else {
            world.sendMessage("§cGame Over. No winners.");
            for (const p of world.getAllPlayers()) {
                try {
                    p.onScreenDisplay.setTitle("§c§lGAME OVER");
                    p.onScreenDisplay.setSubtitle("§7No winners.");
                } catch(e) {}
            }
        }

        world.sendMessage("§7Resetting game in 15 seconds...");
        system.runTimeout(() => { this.stopGame(); }, 300);
    }

    startVictoryCelebration(winner) {
        if (this.victoryInterval) system.clearRun(this.victoryInterval);
        
        let ticks = 0;
        const duration = 200; 

        this.victoryInterval = system.runInterval(() => {
            ticks += 5;
            if (ticks > duration) {
                system.clearRun(this.victoryInterval);
                this.victoryInterval = null;
                return;
            }

            try {
                const dim = winner.dimension;
                const loc = winner.location;

                const rX = loc.x + (Math.random() * 10 - 5);
                const rY = loc.y + (Math.random() * 5);
                const rZ = loc.z + (Math.random() * 10 - 5);

                try {
                    dim.spawnEntity("minecraft:fireworks_rocket", { x: rX, y: rY, z: rZ });
                } catch(e) {}

                dim.runCommand(`playsound firework.launch @a ${rX} ${rY} ${rZ}`);

                system.runTimeout(() => {
                    try {
                        dim.runCommand(`playsound firework.large_blast @a ${rX} ${rY+2} ${rZ}`);
                        dim.runCommand(`playsound firework.twinkle @a ${rX} ${rY+2} ${rZ}`);
                        dim.spawnParticle("minecraft:huge_explosion_emitter", { x: rX, y: rY+2, z: rZ });
                        dim.spawnParticle("minecraft:totem_particle", { x: rX, y: rY+2, z: rZ });
                    } catch(e) {}
                }, 10 + Math.floor(Math.random() * 10));

            } catch (e) {}
        }, 5);
    }

    teleportPlayersToIslands(players) {
        const center = Config.MAP_CENTER;
        const radius = Config.MAP_RADIUS;
        const playerCount = players.length;

        players.forEach((player, index) => {
            const angle = (2 * Math.PI / playerCount) * index;
            const x = Math.round(center.x + radius * Math.cos(angle));
            const z = Math.round(center.z + radius * Math.sin(angle));
            const y = center.y + 1;

            player.teleport({ x, y, z }, { dimension: world.getDimension("overworld") });
            player.sendMessage(`§eYou are Player ${index + 1}. Good luck!`);
            player.setSpawnPoint({ dimension: world.getDimension("overworld"), x, y, z });
        });
    }

    stopGame() {
        this.gameState = "LOBBY";
        this.gameMode = "normal"; 
        if (this.gameLoopInterval) system.clearRun(this.gameLoopInterval);
        
        if (this.victoryInterval) {
            system.clearRun(this.victoryInterval);
            this.victoryInterval = null;
        }

        this.phaseManager.stopGame();
        
        for (const p of world.getAllPlayers()) {
            this.resetPlayerTags(p);
            
            p.runCommand("gamemode adventure");
            p.runCommand("clear");
            p.runCommand("effect @s clear");
            // 【修正】ロビー座標に戻す
            p.teleport({ x: 0, y: -63, z: 0 });
            
            if (this.economy) this.economy.setMoney(p, 0);

            // エンダーチェストの初期化
            try { p.setDynamicProperty("obw_enderchest", undefined); } catch(e) {}
        }
        
        if (this.economy) {
             if (this.lastSurvivorStr) this.economy.resetFakeScore(this.lastSurvivorStr);
             if (this.lastDeadStr) this.economy.resetFakeScore(this.lastDeadStr);
             
             this.lastSurvivorStr = null;
             this.lastDeadStr = null;
        }

        this.mapGenerator.resetMap();
        world.sendMessage("§eGame Stopped & Reset.");

        // ロビーループを再開
        this.startLobbyLoop();
    }

    resetPlayerTags(player) {
        const tagsToRemove = [
            "obw_participant", "obw_eliminated", 
            "obw_auto_miner", "obw_generator", 
            "obw_bought_miner", "obw_bought_generator",
            "obw_bought_scroll", 
            "obw_spectator_processed", 
            "obw_upgrade_void_rescue", "obw_upgrade_absorption", "obw_upgrade_haste",
            "obw_upgrade_jump_boost", "obw_upgrade_speed",
            "obw_unlocked_enderchest" // 追加
        ];
        
        for (const tag of tagsToRemove) {
            player.removeTag(tag);
        }
    }
}