import { world, system, ItemStack, BlockPermutation, EnchantmentTypes } from "@minecraft/server";
import { Config } from "../config.js";
import { LOOT_TABLES } from "../data/loot_tables.js";

// 座標を必ず整数にしてキーを生成する
const getLocKey = (loc) => `${Math.round(loc.x)},${Math.round(loc.y)},${Math.round(loc.z)}`;

export class OneBlockSystem {
    constructor() {
        this.breakCounts = new Map();
        this.oneBlockLocations = new Map();
        this.blockLevels = new Map();
        this.phaseManager = null;
    }

    init() {
        this.loadOneBlocks();
    }

    loadOneBlocks() {
        try {
            const locData = world.getDynamicProperty("obw:one_block_locations");
            if (locData) {
                const parsed = JSON.parse(locData);
                for (const [key, type] of Object.entries(parsed)) this.oneBlockLocations.set(key, type);
            }
            const lvlData = world.getDynamicProperty("obw:one_block_levels");
            if (lvlData) {
                const parsed = JSON.parse(lvlData);
                for (const [key, lvl] of Object.entries(parsed)) this.blockLevels.set(key, lvl);
            }
        } catch (e) {
            console.warn("Failed to load OneBlock data:", e);
        }
    }

    saveOneBlocks() {
        const locData = {};
        for (const [key, type] of this.oneBlockLocations) locData[key] = type;
        world.setDynamicProperty("obw:one_block_locations", JSON.stringify(locData));

        const lvlData = {};
        for (const [key, lvl] of this.blockLevels) lvlData[key] = lvl;
        world.setDynamicProperty("obw:one_block_levels", JSON.stringify(lvlData));
    }

    registerOneBlock(location, type) {
        const key = getLocKey(location);
        this.oneBlockLocations.set(key, type);
        this.blockLevels.set(key, 1);
        this.saveOneBlocks();
        this.breakCounts.set(key, 0);
    }

    unregisterOneBlock(location) {
        const key = getLocKey(location);
        if (this.oneBlockLocations.delete(key)) {
            this.blockLevels.delete(key);
            this.saveOneBlocks();
            this.breakCounts.delete(key);
        }
    }

    clearAll(dimension = null) {
        if (dimension) {
            for (const key of this.oneBlockLocations.keys()) {
                const [x, y, z] = key.split(",").map(Number);
                try {
                    const block = dimension.getBlock({x, y, z});
                    if (block) block.setPermutation(BlockPermutation.resolve("minecraft:air"));
                    const barrier = dimension.getBlock({x, y: y - 1, z});
                    if (barrier) barrier.setPermutation(BlockPermutation.resolve("minecraft:air"));
                } catch (e) {}
            }
        }
        this.oneBlockLocations.clear();
        this.blockLevels.clear();
        this.breakCounts.clear();
        world.setDynamicProperty("obw:one_block_locations", JSON.stringify({}));
        world.setDynamicProperty("obw:one_block_levels", JSON.stringify({}));
    }

    destroyAllHomeBlocks() {
        const dimension = world.getDimension("overworld");
        for (const [key, type] of this.oneBlockLocations) {
            if (type === "home") {
                const [x, y, z] = key.split(",").map(Number);
                try {
                    dimension.getBlock({x, y, z}).setPermutation(BlockPermutation.resolve("minecraft:air"));
                    dimension.spawnParticle("minecraft:huge_explosion_emitter", {x:x+0.5, y:y+0.5, z:z+0.5});
                    world.playSound("random.explode", {x, y, z});
                } catch(e) {}
            }
        }
    }

    getBlockLevel(location) {
        const key = getLocKey(location);
        return this.blockLevels.get(key) || 1;
    }

    upgradeBlock(location) {
        const key = getLocKey(location);
        const current = this.blockLevels.get(key) || 1;
        if (current < 3) {
            this.blockLevels.set(key, current + 1);
            this.saveOneBlocks();
            return true;
        }
        return false;
    }

    getNearestHomeBlock(player) {
        const pLoc = player.location;
        let nearestKey = null;
        let minDistSq = Infinity;

        for (const [key, type] of this.oneBlockLocations) {
            if (type !== "home") continue;
            const [x, y, z] = key.split(",").map(Number);
            const distSq = (pLoc.x - (x+0.5))**2 + (pLoc.y - y)**2 + (pLoc.z - (z+0.5))**2;
            if (distSq < minDistSq) {
                minDistSq = distSq;
                nearestKey = key;
            }
        }
        
        if (nearestKey && minDistSq <= 25) {
            const [x, y, z] = nearestKey.split(",").map(Number);
            return { x, y, z };
        }
        return null;
    }

    isPlayerNearOneBlock(player, type = "home", radius = 5) {
        if (!player) return false;
        const pLoc = player.location;
        const radiusSq = radius * radius;

        for (const [key, blockType] of this.oneBlockLocations) {
            if (blockType !== type) continue;
            const [x, y, z] = key.split(",").map(Number);
            const distSq = (pLoc.x - (x + 0.5)) ** 2 + (pLoc.y - y) ** 2 + (pLoc.z + 0.5) ** 2;
            if (distSq <= radiusSq) return true;
        }
        return false;
    }

    // 【追加】爆発で消えたOneBlockを復元するメソッド
    restoreExplodedBlock(blockLocation) {
        const key = getLocKey(blockLocation);
        if (!this.oneBlockLocations.has(key)) return;

        const type = this.oneBlockLocations.get(key);
        // サドンデス中はHomeBlockは復活させない
        if (type === "home" && this.phaseManager && this.phaseManager.currentPhase === 4) {
            return;
        }

        const dimension = world.getDimension("overworld");
        
        // 既にブロックがある場合は何もしない(二重処理防止)
        try {
            const currentBlock = dimension.getBlock(blockLocation);
            if (currentBlock && currentBlock.typeId !== "minecraft:air") return;
        } catch(e) {}

        const count = this.breakCounts.get(key) || 0;
        // 爆発時はカウントを進めずに元の状態に戻す(または次のブロックを出す)
        // ここでは「キャンセル時の動作」を応用して即座に修復する
        this.regenerateBlock(dimension, blockLocation, "mid", null, type, count, true);
    }

    // 鉱石ブロックIDからドロップアイテムIDへの変換ヘルパー
    convertBlockToDrop(blockId) {
        const mapping = {
            "minecraft:coal_ore": "minecraft:coal",
            "minecraft:deepslate_coal_ore": "minecraft:coal",
            "minecraft:iron_ore": "minecraft:raw_iron",
            "minecraft:deepslate_iron_ore": "minecraft:raw_iron",
            "minecraft:gold_ore": "minecraft:raw_gold",
            "minecraft:deepslate_gold_ore": "minecraft:raw_gold",
            "minecraft:copper_ore": "minecraft:raw_copper",
            "minecraft:deepslate_copper_ore": "minecraft:raw_copper",
            "minecraft:diamond_ore": "minecraft:diamond",
            "minecraft:deepslate_diamond_ore": "minecraft:diamond",
            "minecraft:emerald_ore": "minecraft:emerald",
            "minecraft:deepslate_emerald_ore": "minecraft:emerald",
            "minecraft:lapis_ore": "minecraft:lapis_lazuli",
            "minecraft:deepslate_lapis_ore": "minecraft:lapis_lazuli",
            "minecraft:redstone_ore": "minecraft:redstone",
            "minecraft:deepslate_redstone_ore": "minecraft:redstone",
            // 【修正】レッドストーン鉱石が発光状態(lit_redstone_ore)のIDで返ってくる場合に対応
            "minecraft:lit_redstone_ore": "minecraft:redstone",
            "minecraft:lit_deepslate_redstone_ore": "minecraft:redstone",
            
            "minecraft:quartz_ore": "minecraft:quartz",
            "minecraft:nether_gold_ore": "minecraft:gold_nugget",
            // V2.0 追加変換 (石系・草)
            "minecraft:stone": "minecraft:cobblestone",
            "minecraft:grass_block": "minecraft:dirt",
            "minecraft:deepslate": "minecraft:cobbled_deepslate"
        };
        return mapping[blockId] || blockId;
    }

    onBlockBreak(event) {
        const { block, dimension, player } = event;
        const key = getLocKey(block.location);

        if (!this.oneBlockLocations.has(key)) return;

        const type = this.oneBlockLocations.get(key);
        
        if (type === "mid" && this.phaseManager && this.phaseManager.currentPhase === 1) {
            player.sendMessage("§cMid mining is disabled in Phase 1!");
            system.runTimeout(() => {
                try {
                    const { x, y, z } = block.location;
                    dimension.runCommand(`kill @e[type=item,x=${x},y=${y},z=${z},r=3]`);
                } catch(e) {}
            }, 2);
            this.regenerateBlock(dimension, block.location, "mid", player, type, 0, true);
            return;
        }

        if (type === "home" && this.phaseManager && this.phaseManager.currentPhase === 4) {
            return;
        }

        // --- Blitzモード用: ブロック資源5倍処理 ---
        // 破壊されたブロックのIDを取得し、チェストや危険物以外なら4個追加でスポーンさせる
        if (this.phaseManager && this.phaseManager.gameMode === "blitz") {
             const blockTypeId = event.brokenBlockPermutation.type.id;
             const ignoredBlocks = [
                 "minecraft:chest", "minecraft:tnt", "minecraft:bedrock", "minecraft:barrier",
                 "minecraft:shulker_box", "minecraft:barrel"
             ];
             
             if (!ignoredBlocks.includes(blockTypeId)) {
                 try {
                     const spawnPos = { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 };
                     
                     // 鉱石なら原石などに変換してドロップさせる
                     const dropItemId = this.convertBlockToDrop(blockTypeId);
                     
                     // 4個追加 (バニラドロップ1個 + 追加4個 = 5個)
                     dimension.spawnItem(new ItemStack(dropItemId, 4), spawnPos);
                 } catch(e) {
                     // エラー無視 (アイテムID不正など)
                 }
             }
        }
        // ------------------------------------------

        let count = this.breakCounts.get(key) || 0;
        count++;
        this.breakCounts.set(key, count);

        const level = this.blockLevels.get(key) || 1;
        let lootTableKey = (type === "mid") ? "mid" : `level_${level}`;

        this.regenerateBlock(dimension, block.location, lootTableKey, player, type, count, false);
    }

    regenerateBlock(dimension, location, lootTableKey, player, type, breakCount, isCancel = false) {
        // Midブロックの場合、破壊直後に岩盤を置いて「待機中」演出にする
        if (type === "mid" && !isCancel) {
            try {
                const block = dimension.getBlock(location);
                if (block) {
                    block.setPermutation(BlockPermutation.resolve("minecraft:bedrock"));
                }
            } catch (e) {}
        }

        const performRegeneration = () => {
            try {
                let result;
                
                if (isCancel) {
                    // キャンセルまたは爆発復旧時は、Midなら金ブロック、Homeなら草ブロックに戻す
                    if (type === "mid") {
                        result = { id: Config.MID_BLOCK, type: "block", weight: 1 };
                    } else {
                        // Homeの場合はレベルに関わらず一貫性を保つため土台となるブロックを置く
                        result = { id: Config.INITIAL_BLOCK, type: "block", weight: 1 };
                    }
                } 
                else {
                    const lootTable = LOOT_TABLES[lootTableKey] || LOOT_TABLES["level_1"];
                    result = this.weightedRandom(lootTable);
                }

                let blockToPlace = "minecraft:grass_block";
                if (result.type === "block") blockToPlace = result.id;
                else blockToPlace = "minecraft:dirt";

                const block = dimension.getBlock(location);
                block.setPermutation(BlockPermutation.resolve(blockToPlace));
                
                if (blockToPlace === "minecraft:chest") {
                    const isMid = (type === "mid");
                    this.fillChest(block, isMid);
                }

                if (type === "home" && player) {
                    const pLoc = player.location;
                    if (pLoc.y >= location.y - 0.5) {
                         const blockCenter = { x: location.x + 0.5, z: location.z + 0.5 };
                         const distSq = (pLoc.x - blockCenter.x) ** 2 + (pLoc.z - blockCenter.z) ** 2;
                         if (distSq < 1.44) {
                             const rotation = player.getRotation();
                             player.teleport(
                                 { x: location.x + 0.5, y: location.y + 1.0, z: location.z + 0.5 },
                                 { dimension: dimension, rotation: rotation, checkForBlocks: false, keepVelocity: false }
                             );
                         }
                    }
                }

                if (!isCancel) {
                    try { dimension.spawnParticle("minecraft:villager_happy", { x: location.x + 0.5, y: location.y + 1, z: location.z + 0.5 }); } catch(e){}
                    
                    const spawnPos = { x: location.x + 0.5, y: location.y + 1.2, z: location.z + 0.5 };
                    if (result.type === "item") {
                        // --- Blitzモード用: アイテムドロップ5倍 ---
                        let amount = 1;
                        if (this.phaseManager && this.phaseManager.gameMode === "blitz") {
                            amount = 5;
                        }
                        
                        try {
                            dimension.spawnItem(new ItemStack(result.id, amount), spawnPos);
                        } catch(e) {
                            // エラー(スタック不可アイテム等)の場合は1個ずつ出す
                            for (let i = 0; i < amount; i++) {
                                dimension.spawnItem(new ItemStack(result.id, 1), spawnPos);
                            }
                        }
                    } else if (result.type === "entity") {
                        dimension.spawnEntity(result.id, spawnPos);
                    }
                }

            } catch (e) {
                console.warn(`OneBlock Error: ${e}`);
            }
        };

        if (type === "mid" && !isCancel) {
            system.runTimeout(() => performRegeneration(), 100);
        } else {
            performRegeneration();
        }
    }

    fillChest(block, isMid = false) {
        try {
            const container = block.getComponent("inventory").container;
            if (!container) return;

            let availableSlots = Array.from({length: container.size}, (_, i) => i);
            for (let i = availableSlots.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [availableSlots[i], availableSlots[j]] = [availableSlots[j], availableSlots[i]];
            }

            if (isMid) {
                const netheriteItems = [
                    "minecraft:netherite_sword", "minecraft:netherite_chestplate", 
                    "minecraft:netherite_leggings", "minecraft:netherite_boots", "minecraft:netherite_helmet"
                ];
                const enchantBooks = [
                    "book:sharpness_v", "book:protection_iv", "book:efficiency_v",
                    "book:density_v", "book:breach_iv", "book:wind_burst_iii",
                    "book:lunge_iii"
                ];
                const fillerItems = [
                    "minecraft:diamond", "minecraft:gold_block", "minecraft:golden_apple",
                    "minecraft:iron_ingot", "minecraft:arrow"
                ];

                const totalCount = Math.floor(Math.random() * 3) + 3; 
                let addedCount = 0;

                if (Math.random() < 0.5 && addedCount < totalCount) {
                    const id = netheriteItems[Math.floor(Math.random() * netheriteItems.length)];
                    this.setItemToContainer(container, availableSlots.pop(), id, 1);
                    addedCount++;
                }

                if (Math.random() < 0.5 && addedCount < totalCount) {
                    const id = enchantBooks[Math.floor(Math.random() * enchantBooks.length)];
                    this.setItemToContainer(container, availableSlots.pop(), id, 1);
                    addedCount++;
                }

                while (addedCount < totalCount) {
                    const id = fillerItems[Math.floor(Math.random() * fillerItems.length)];
                    this.setItemToContainer(container, availableSlots.pop(), id, 1);
                    addedCount++;
                }

            } else {
                const items = [
                    "minecraft:apple", "minecraft:bread", "minecraft:cooked_beef",
                    "minecraft:oak_log", "minecraft:cobblestone", "minecraft:iron_ingot",
                    "minecraft:gold_ingot", "minecraft:iron_ingot", 
                    "minecraft:arrow", "minecraft:sapling", "minecraft:bone"
                ];

                const count = Math.floor(Math.random() * 3) + 3;
                for (let i = 0; i < count; i++) {
                    const id = items[Math.floor(Math.random() * items.length)];
                    const amount = Math.floor(Math.random() * 3) + 1;
                    this.setItemToContainer(container, availableSlots.pop(), id, amount);
                }
            }
        } catch(e) {}
    }

    setItemToContainer(container, slot, itemId, amount) {
        if (slot === undefined) return;
        try {
            let itemStack;
            if (itemId.startsWith("book:")) {
                itemStack = new ItemStack("minecraft:enchanted_book", 1);
                const enchantable = itemStack.getComponent("minecraft:enchantable");
                
                if (itemId === "book:sharpness_v") enchantable.addEnchantment({ type: EnchantmentTypes.get("sharpness"), level: 5 });
                if (itemId === "book:protection_iv") enchantable.addEnchantment({ type: EnchantmentTypes.get("protection"), level: 4 });
                if (itemId === "book:efficiency_v") enchantable.addEnchantment({ type: EnchantmentTypes.get("efficiency"), level: 5 });
                
                try {
                    if (itemId === "book:density_v") enchantable.addEnchantment({ type: EnchantmentTypes.get("density"), level: 5 });
                    if (itemId === "book:breach_iv") enchantable.addEnchantment({ type: EnchantmentTypes.get("breach"), level: 4 });
                    if (itemId === "book:wind_burst_iii") enchantable.addEnchantment({ type: EnchantmentTypes.get("wind_burst"), level: 3 });
                } catch(e) {}

                try {
                    if (itemId === "book:lunge_iii") enchantable.addEnchantment({ type: EnchantmentTypes.get("lunge"), level: 3 });
                } catch(e) {}

            } else {
                itemStack = new ItemStack(itemId, amount);
            }
            container.setItem(slot, itemStack);
        } catch(e) {}
    }

    weightedRandom(items) {
        const totalWeight = items.reduce((sum, item) => sum + item.weight, 0);
        let random = Math.random() * totalWeight;
        for (const item of items) {
            if (random < item.weight) return item;
            random -= item.weight;
        }
        return items[0];
    }
}