package com.playerblocklife;

import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Skull;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Rotatable;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.util.Vector;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 玩家方块管理器 - 负责管理玩家生命方块的核心组件
 * 
 * <p>主要职责：
 * <ul>
 *   <li>生成和放置玩家生命方块</li>
 *   <li>管理方块位置和所有者映射关系</li>
 *   <li>处理方块破坏和恢复逻辑</li>
 *   <li>提供方块数据持久化存储</li>
 *   <li>支持方块位置查询和验证</li>
 *   <li>与SkinManager协同工作，确保方块正确显示玩家皮肤</li>
 * </ul>
 * 
 * <p><b>SkinsRestorer集成特性：</b>
 * <ul>
 *   <li>通过SkinManager获取SkinsRestorer提供的玩家皮肤纹理</li>
 *   <li>确保离线服务器上的方块显示正确的自定义皮肤</li>
 *   <li>支持异步皮肤加载，避免方块放置阻塞</li>
 *   <li>提供皮肤加载状态检查，确保皮肤就绪后再放置方块</li>
 * </ul>
 * 
 * <p>使用并发安全的数据结构确保多线程环境下的数据一致性。</p>
 * 
 * @author xiaobai
 * @version 2.2.0
 * @since 1.0.0
 */
public class PlayerBlockManager {
    private final PlayerBlockLife plugin;
    private final SkinManager skinManager;
    private final Map<UUID, List<Location>> playerBlocks = new ConcurrentHashMap<>();
    private final Map<Location, UUID> blockOwners = new ConcurrentHashMap<>();
    private final Map<UUID, Material> playerBlockTypes = new ConcurrentHashMap<>();
    private final File dataFile;
    private final Random random = new Random();

    public PlayerBlockManager(PlayerBlockLife plugin, SkinManager skinManager) {
        this.plugin = plugin;
        this.skinManager = skinManager;
        this.dataFile = new File(plugin.getDataFolder(), "blockdata.yml");
    }

    /**
     * 为玩家设置生命方块（兼容旧方法）
     */
    public boolean setLifeBlocks(Player player, Location center) {
        ConfigManager config = plugin.getConfigManager();
        boolean requireOpenSky = true; // 使用默认值，因为配置已移除
        int maxAttempts = 50; // 使用默认值，因为配置已移除
        
        return generateLifeBlocksForPlayer(player, 5, 5, requireOpenSky, maxAttempts);
    }

    /**
     * 为玩家生成指定数量的生命方块
     * 
     * <p>此方法负责生成玩家的生命方块，包括以下步骤：
     * <ol>
     *   <li>检查玩家是否已有生命方块</li>
     *   <li>验证玩家皮肤是否已从SkinsRestorer或其他来源加载完成</li>
     *   <li>在指定范围内寻找合适的放置位置</li>
     *   <li>放置带有玩家皮肤纹理的玩家头颅方块</li>
     *   <li>记录方块位置和所有者关系</li>
     *   <li>保存数据并返回生成结果</li>
     * </ol>
     * </p>
     * 
     * <p><b>皮肤加载检查：</b>
     * <ul>
     *   <li>调用skinManager.isSkinLoaded()检查皮肤是否就绪</li>
     *   <li>如果皮肤未加载，方块生成将失败</li>
     *   <li>确保离线服务器通过SkinsRestorer获取的皮肤能正确应用</li>
     *   <li>避免放置默认Steve皮肤的方块</li>
     * </ul>
     * </p>
     * 
     * @param player 目标玩家
     * @param blockAmount 要生成的方块数量
     * @param spreadRange 生成范围（以玩家为中心的正方形边长的一半）
     * @param requireOpenSky 是否需要开阔天空（上方无方块覆盖）
     * @param maxAttempts 寻找合适位置的最大尝试次数
     * @return 生成成功返回true，失败返回false
     * @see SkinManager#isSkinLoaded(UUID)
     * @see SkinManager#getSkinFromSkinsRestorer(Player)
     */
    public boolean generateLifeBlocksForPlayer(Player player, int blockAmount, int spreadRange, boolean requireOpenSky, int maxAttempts) {
        UUID playerId = player.getUniqueId();
        String playerName = player.getName();

        // 检查是否已有生命方块
        if (hasLifeBlocks(playerId)) {
            return false;
        }

        // 检查玩家皮肤是否已加载
        if (!skinManager.isSkinLoaded(playerId)) {
            return false;
        }

        List<Location> blocks = new ArrayList<>();
        int blocksPlaced = 0;
        int attempts = 0;

        // 尝试生成指定数量的方块
        while (blocksPlaced < blockAmount && attempts < maxAttempts) {
            Location blockLoc = findSurfaceLocation(player.getLocation(), spreadRange, requireOpenSky);
            attempts++;

            if (blockLoc != null && placePlayerHead(blockLoc, playerId, playerName)) {
                blocks.add(blockLoc);
                blockOwners.put(blockLoc, playerId);
                blocksPlaced++;

                // 添加放置效果
                spawnPlaceEffects(blockLoc);
            }
        }

        if (blocksPlaced > 0) {
            playerBlocks.put(playerId, blocks);
            saveData();
            return true;
        } else {
            return false;
        }
    }

    /**
     * 寻找地表位置（放宽条件，只要是露天地面就可以）
     */
    private Location findSurfaceLocation(Location center, int spreadRange, boolean requireOpenSky) {
        for (int i = 0; i < 20; i++) { // 增加尝试次数
            int x = random.nextInt(spreadRange * 2 + 1) - spreadRange;
            int z = random.nextInt(spreadRange * 2 + 1) - spreadRange;

            // 以玩家坐标为中心，但高度从世界最高点开始寻找
            Location testLoc = center.clone().add(x, 0, z);
            World world = testLoc.getWorld();
            if (world == null) continue;

            // 从世界最高点向下寻找第一个固体方块
            int maxHeight = world.getMaxHeight();
            Block groundBlock = null;
            for (int y = maxHeight; y > world.getMinHeight(); y--) {
                testLoc.setY(y);
                Block block = testLoc.getBlock();
                Material type = block.getType();
                
                // 检查是否是固体方块（可以作为支撑）
                if (type.isSolid() && type.isBlock() && !type.isTransparent()) {
                    groundBlock = block;
                    break;
                }
            }

            if (groundBlock == null) continue;

            // 地表位置 = 固体方块上方一格
            Location surfaceLoc = groundBlock.getLocation().add(0, 1, 0);
            
            // 检查是否已有方块
            if (blockOwners.containsKey(surfaceLoc)) {
                continue;
            }

            // 检查位置是否合适（放宽条件）
            if (!isSuitableLocationRelaxed(surfaceLoc)) {
                continue;
            }

            // 如果需要上方无方块覆盖，检查上方3格
            if (requireOpenSky) {
                boolean hasCover = false;
                for (int y = 1; y <= 3; y++) {
                    Block aboveBlock = surfaceLoc.clone().add(0, y, 0).getBlock();
                    if (!aboveBlock.getType().isAir()) {
                        hasCover = true;
                        break;
                    }
                }
                if (hasCover) continue;
            }

            return surfaceLoc;
        }
        return null;
    }

    /**
     * 寻找合适的位置
     */
    private Location findSuitableLocation(Location center) {
        for (int i = 0; i < 10; i++) {
            int x = random.nextInt(11) - 5; // -5 到 5
            int z = random.nextInt(11) - 5;

            Location testLoc = center.clone().add(x, -1, z);
            Block block = testLoc.getBlock();

            // 检查位置是否合适
            if (isSuitableLocation(testLoc)) {
                return testLoc;
            }
        }
        return null;
    }

    /**
     * 检查位置是否合适
     * 修复：移除 isReplaceable() 方法调用
     */
    private boolean isSuitableLocation(Location location) {
        Block block = location.getBlock();

        // 检查是否已有方块
        if (blockOwners.containsKey(location)) {
            return false;
        }

        // 检查方块是否可替换（修复了 isReplaceable() 方法不存在的问题）
        Material type = block.getType();
        if (!type.isAir()) {
            // 检查是否是固体方块，固体方块不能替换
            if (type.isSolid()) {
                return false;
            }

            // 检查是否是液体
            if (type == Material.WATER || type == Material.LAVA ||
                    type == Material.WATER_CAULDRON || type == Material.LAVA_CAULDRON) {
                return false;
            }

            // 检查一些特定的不可替换方块
            switch (type) {
                case FIRE:
                case SOUL_FIRE:
                case COBWEB:
                case BAMBOO:
                case BAMBOO_SAPLING:
                case SCAFFOLDING:
                case LADDER:
                case VINE:
                case TWISTING_VINES:
                case WEEPING_VINES:
                case GLOW_LICHEN:
                    // 这些方块可以替换
                    break;
                default:
                    // 如果不是固体，也不是特定的透明方块，也不是空气，则检查是否是透明方块
                    if (!type.isTransparent()) {
                        return false;
                    }
                    break;
            }
        }

        // 检查下方是否有支撑方块
        Block below = location.clone().add(0, -1, 0).getBlock();
        Material belowType = below.getType();

        if (belowType.isAir() || !belowType.isSolid()) {
            return false;
        }

        // 检查是否在水或岩浆中
        if (block.isLiquid() || below.isLiquid()) {
            return false;
        }

        return true;
    }

    /**
     * 放宽条件的检查方法（用于新的生成逻辑）
     */
    private boolean isSuitableLocationRelaxed(Location location) {
        Block block = location.getBlock();

        // 检查是否已有方块
        if (blockOwners.containsKey(location)) {
            return false;
        }

        // 检查方块是否可替换（放宽条件）
        Material type = block.getType();
        if (!type.isAir()) {
            // 固体方块不能替换
            if (type.isSolid()) {
                return false;
            }

            // 液体方块不能替换
            if (type == Material.WATER || type == Material.LAVA) {
                return false;
            }
        }

        // 检查下方是否有支撑方块（放宽条件）
        Block below = location.clone().add(0, -1, 0).getBlock();
        Material belowType = below.getType();

        // 只要下方不是空气或液体就可以
        if (belowType.isAir() || belowType == Material.WATER || belowType == Material.LAVA) {
            return false;
        }

        return true;
    }

    /**
     * 放置玩家头颅方块
     * 
     * <p>使用SkinManager创建带有正确皮肤的玩家头颅方块，支持离线服务器皮肤显示。</p>
     * 
     * @param location 放置位置
     * @param playerId 玩家UUID
     * @param playerName 玩家名称
     * @return 放置成功返回true，失败返回false
     */
    private boolean placePlayerHead(Location location, UUID playerId, String playerName) {
        try {
            Block block = location.getBlock();

            // 检查方块是否已被占用
            if (blockOwners.containsKey(location)) {
                return false;
            }

            // 检查玩家皮肤是否已加载
            if (!skinManager.isSkinLoaded(playerId)) {
                plugin.logWarning("玩家 " + playerName + " 的皮肤未加载，无法放置头颅方块");
                return false;
            }

            // 设置方块为玩家头颅
            block.setType(Material.PLAYER_HEAD);

            // 获取并设置头颅数据
            Skull skullState = (Skull) block.getState();
            
            // 使用SkinManager创建玩家头颅物品，然后应用到方块上
            ItemStack headItem = skinManager.createPlayerHead(playerId, playerName);
            SkullMeta itemMeta = (SkullMeta) headItem.getItemMeta();
            
            if (itemMeta != null) {
                // 获取物品的玩家档案并应用到方块上
                org.bukkit.profile.PlayerProfile profile = itemMeta.getPlayerProfile();
                if (profile != null) {
                    skullState.setOwnerProfile(profile);
                } else {
                    // 如果无法获取档案，回退到使用离线玩家
                    OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerId);
                    skullState.setOwningPlayer(offlinePlayer);
                }
            } else {
                // 如果物品元数据为空，使用离线玩家
                OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerId);
                skullState.setOwningPlayer(offlinePlayer);
            }

            // 设置朝向（随机方向）
            BlockData blockData = block.getBlockData();
            if (blockData instanceof Rotatable) {
                Rotatable rotatable = (Rotatable) blockData;
                BlockFace[] faces = {BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST};
                rotatable.setRotation(faces[random.nextInt(faces.length)]);
                block.setBlockData(rotatable);
            }

            // 更新方块
            skullState.update(true, false);

            plugin.logInfo("成功放置玩家头颅方块: " + playerName + " 在 " + location);
            return true;
        } catch (Exception e) {
            plugin.logError("放置玩家头颅失败: " + location, e);
            return false;
        }
    }

    /**
     * 生成放置效果
     */
    private void spawnPlaceEffects(Location location) {
        World world = location.getWorld();
        if (world == null) return;

        // 粒子效果
        world.spawnParticle(Particle.ENCHANTMENT_TABLE,
                location.clone().add(0.5, 0.5, 0.5),
                30, 0.3, 0.3, 0.3, 0.1);

        // 音效
        world.playSound(location, Sound.BLOCK_ANVIL_PLACE, 0.5f, 1.2f);
    }

    /**
     * 检查方块是否属于某个玩家
     */
    public UUID getBlockOwner(Location location) {
        return blockOwners.get(location);
    }

    /**
     * 移除方块（当被挖掘时）
     */
    public boolean removeBlock(Location location, Player breaker) {
        UUID ownerId = blockOwners.get(location);
        if (ownerId == null) {
            return false;
        }

        List<Location> blocks = playerBlocks.get(ownerId);
        if (blocks == null || !blocks.contains(location)) {
            return false;
        }

        // 移除方块
        blocks.remove(location);
        blockOwners.remove(location);

        // 设置方块为空气
        location.getBlock().setType(Material.AIR);

        // 生成破坏效果
        spawnBreakEffects(location, breaker);

        // 检查玩家是否还有剩余方块
        int remaining = blocks.size();

        // 通知所有相关玩家
        notifyBlockBreak(ownerId, breaker, remaining);

        // 保存数据
        saveData();

        return true;
    }

    /**
     * 生成破坏效果
     */
    private void spawnBreakEffects(Location location, Player breaker) {
        World world = location.getWorld();
        if (world == null) return;

        // 粒子效果
        world.spawnParticle(Particle.BLOCK_CRACK,
                location.clone().add(0.5, 0.5, 0.5),
                50, 0.5, 0.5, 0.5, 0.5, Material.PLAYER_HEAD.createBlockData());

        world.spawnParticle(Particle.SMOKE_LARGE,
                location.clone().add(0.5, 0.5, 0.5),
                20, 0.3, 0.3, 0.3, 0.05);

        // 音效
        world.playSound(location, Sound.ENTITY_ITEM_BREAK, 1.0f, 0.8f);
        world.playSound(location, Sound.BLOCK_GLASS_BREAK, 0.8f, 1.0f);

        // 对挖掘者造成轻微击退
        if (breaker != null) {
            Location breakerLoc = breaker.getLocation();
            Vector direction = location.toVector().subtract(breakerLoc.toVector()).normalize();
            breaker.setVelocity(direction.multiply(-0.5).setY(0.3));
        }
    }

    /**
     * 通知方块被破坏
     */
    private void notifyBlockBreak(UUID ownerId, Player breaker, int remaining) {
        Player owner = Bukkit.getPlayer(ownerId);
        String ownerName = Bukkit.getOfflinePlayer(ownerId).getName();

        // 通知方块所有者
        if (owner != null && owner.isOnline()) {
            owner.sendMessage("§c⚠ 警告！你的生命方块被破坏了！");
            owner.sendMessage("§7破坏者: §e" + (breaker != null ? breaker.getName() : "未知"));
            owner.sendMessage("§7剩余生命方块: §a" + remaining + " §7/ §c5");

            if (remaining <= 2) {
                owner.sendMessage("§4⚠ 警告！生命方块即将耗尽！");
            }

            // 播放警告音效
            owner.playSound(owner.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 0.8f, 0.5f);
        }

        // 通知破坏者
        if (breaker != null && !breaker.getUniqueId().equals(ownerId)) {
            breaker.sendMessage("§6你破坏了一个生命方块！");
            breaker.sendMessage("§7所有者: §e" + (ownerName != null ? ownerName : "未知玩家"));
            breaker.sendMessage("§7对方剩余生命方块: §a" + remaining);

            // 给予挖掘者经验奖励
            breaker.giveExp(5);
            breaker.playSound(breaker.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);
        }

        // 广播给附近玩家
        World world = owner != null ? owner.getWorld() : (breaker != null ? breaker.getWorld() : null);
        if (world != null) {
            for (Player nearby : world.getPlayers()) {
                if (nearby != owner && nearby != breaker &&
                        nearby.getLocation().distance(owner != null ? owner.getLocation() : breaker.getLocation()) < 30) {
                    nearby.sendMessage("§7[附近] §e一个生命方块被破坏了！");
                }
            }
        }
    }

    /**
     * 获取玩家剩余方块数量
     */
    public int getRemainingBlocks(UUID playerId) {
        List<Location> blocks = playerBlocks.get(playerId);
        return blocks != null ? blocks.size() : 0;
    }

    /**
     * 检查玩家是否有生命方块
     */
    public boolean hasLifeBlocks(UUID playerId) {
        List<Location> blocks = playerBlocks.get(playerId);
        return blocks != null && !blocks.isEmpty();
    }

    /**
     * 获取玩家的所有生命方块位置
     */
    public List<Location> getPlayerBlocks(UUID playerId) {
        return playerBlocks.getOrDefault(playerId, new ArrayList<>());
    }

    /**
     * 清除玩家的所有生命方块
     */
    public void clearPlayerBlocks(UUID playerId) {
        List<Location> blocks = playerBlocks.remove(playerId);
        if (blocks != null) {
            for (Location loc : blocks) {
                blockOwners.remove(loc);
                loc.getBlock().setType(Material.AIR);
            }
        }
        saveData();
    }

    /**
     * 重新生成玩家的生命方块
     */
    public boolean regeneratePlayerBlocks(Player player) {
        UUID playerId = player.getUniqueId();

        // 清除旧方块
        clearPlayerBlocks(playerId);

        // 生成新方块
        return setLifeBlocks(player, player.getLocation());
    }

    /**
     * 获取已注册玩家的数量
     */
    public int getPlayerBlocksCount() {
        return playerBlocks.size();
    }

    /**
     * 获取总方块数量
     */
    public int getTotalBlocksCount() {
        int total = 0;
        for (List<Location> blocks : playerBlocks.values()) {
            total += blocks.size();
        }
        return total;
    }

    /**
     * 加载数据
     */
    @SuppressWarnings("unchecked")
    public void loadData() {
        if (!dataFile.exists()) {
            return;
        }

        try {
            Yaml yaml = new Yaml();
            Map<String, Object> data = yaml.load(new FileReader(dataFile));

            if (data == null) {
                return;
            }

            // 加载方块数据
            if (data.containsKey("blocks")) {
                Map<String, List<Map<String, Object>>> blocksData =
                        (Map<String, List<Map<String, Object>>>) data.get("blocks");

                for (Map.Entry<String, List<Map<String, Object>>> entry : blocksData.entrySet()) {
                    UUID playerId = UUID.fromString(entry.getKey());
                    List<Location> locations = new ArrayList<>();

                    for (Map<String, Object> locData : entry.getValue()) {
                        String worldName = (String) locData.get("world");
                        double x = (double) locData.get("x");
                        double y = (double) locData.get("y");
                        double z = (double) locData.get("z");

                        World world = Bukkit.getWorld(worldName);
                        if (world != null) {
                            Location location = new Location(world, x, y, z);
                            locations.add(location);
                            blockOwners.put(location, playerId);
                        }
                    }

                    if (!locations.isEmpty()) {
                        playerBlocks.put(playerId, locations);
                    }
                }
            }

            plugin.logInfo("已加载 " + playerBlocks.size() + " 个玩家的方块数据");
            plugin.logInfo("总共 " + blockOwners.size() + " 个生命方块");

        } catch (Exception e) {
            plugin.logError("加载方块数据失败", e);
        }
    }

    /**
     * 保存数据
     */
    public void saveData() {
        try {
            Map<String, Object> data = new HashMap<>();
            Map<String, List<Map<String, Object>>> blocksData = new HashMap<>();

            // 保存方块数据
            for (Map.Entry<UUID, List<Location>> entry : playerBlocks.entrySet()) {
                String playerId = entry.getKey().toString();
                List<Map<String, Object>> locations = new ArrayList<>();

                for (Location loc : entry.getValue()) {
                    Map<String, Object> locData = new HashMap<>();
                    locData.put("world", loc.getWorld().getName());
                    locData.put("x", loc.getX());
                    locData.put("y", loc.getY());
                    locData.put("z", loc.getZ());
                    locations.add(locData);
                }

                blocksData.put(playerId, locations);
            }

            data.put("blocks", blocksData);

            // 写入文件
            Yaml yaml = new Yaml();
            yaml.dump(data, new FileWriter(dataFile));

        } catch (Exception e) {
            plugin.logError("保存方块数据失败", e);
        }
    }

    /**
     * 获取所有玩家的方块数据
     */
    public Map<UUID, List<Location>> getAllPlayerBlocks() {
        return new HashMap<>(playerBlocks);
    }

    /**
     * 获取所有方块的位置和所有者
     */
    public Map<Location, UUID> getAllBlockOwners() {
        return new HashMap<>(blockOwners);
    }

    /**
     * 检查位置是否包含生命方块
     */
    public boolean isLifeBlock(Location location) {
        return blockOwners.containsKey(location);
    }

    /**
     * 获取玩家的生命方块位置列表（用于显示）
     */
    public List<String> getPlayerBlockLocations(UUID playerId) {
        List<Location> blocks = playerBlocks.get(playerId);
        List<String> locations = new ArrayList<>();

        if (blocks != null) {
            for (Location loc : blocks) {
                String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "未知世界";
                locations.add(String.format("世界: %s, 坐标: %d, %d, %d",
                        worldName,
                        loc.getBlockX(),
                        loc.getBlockY(),
                        loc.getBlockZ()));
            }
        }

        return locations;
    }

    /**
     * 获取距离玩家最近的方块
     */
    public Location getNearestBlock(Player player) {
        UUID playerId = player.getUniqueId();
        List<Location> blocks = playerBlocks.get(playerId);

        if (blocks == null || blocks.isEmpty()) {
            return null;
        }

        Location nearest = null;
        double nearestDistance = Double.MAX_VALUE;

        for (Location block : blocks) {
            double distance = player.getLocation().distance(block);
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearest = block;
            }
        }

        return nearest;
    }

    /**
     * 获取所有生命方块的统计信息
     */
    public Map<String, Object> getStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalPlayers", playerBlocks.size());
        stats.put("totalBlocks", blockOwners.size());

        // 按世界统计
        Map<String, Integer> blocksPerWorld = new HashMap<>();
        for (Location loc : blockOwners.keySet()) {
            String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "unknown";
            blocksPerWorld.put(worldName, blocksPerWorld.getOrDefault(worldName, 0) + 1);
        }
        stats.put("blocksPerWorld", blocksPerWorld);

        return stats;
    }
}