package com.playerblocklife;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.profile.PlayerProfile;
import org.bukkit.profile.PlayerTextures;
import org.yaml.snakeyaml.Yaml;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 皮肤管理器 - 负责玩家皮肤的获取、缓存和应用
 * 
 * <p>主要功能：
 * <ul>
 *   <li>从多种来源获取玩家皮肤数据（SkinsRestorer插件、PlayerProfile、本地缓存）</li>
 *   <li>皮肤数据Base64编码和缓存管理</li>
 *   <li>自定义模型数据分配和管理</li>
 *   <li>异步皮肤加载避免阻塞主线程</li>
 *   <li>皮肤缓存过期清理</li>
 *   <li>完整的SkinsRestorer插件集成支持</li>
 * </ul>
 * 
 * <p>皮肤获取优先级（根据配置的source字段）：
 * <ol>
 *   <li><b>skinsrestorer</b>：优先从SkinsRestorer插件获取皮肤纹理数据</li>
 *   <li><b>player_profile</b>：优先使用Bukkit的PlayerProfile API</li>
 *   <li><b>local_cache</b>：优先从本地缓存加载</li>
 *   <li>默认Steve皮肤（所有来源都失败时的备用）</li>
 * </ol>
 * 
 * <p><b>SkinsRestorer集成特性：</b>
 * <ul>
 *   <li>自动检测SkinsRestorer插件是否安装</li>
 *   <li>使用反射安全调用SkinsRestorer API，避免硬依赖</li>
 *   <li>获取完整的皮肤纹理数据（value和signature）</li>
 *   <li>支持离线服务器，避免默认Steve皮肤问题</li>
 *   <li>优雅降级：SkinsRestorer失败时自动回退到其他来源</li>
 * </ul>
 * 
 * <p>皮肤缓存默认保留7天，过期后自动重新获取。</p>
 * 
 * @author xiaobai
 * @version 2.2.0
 * @since 1.0.0
 */
public class SkinManager {
    private final PlayerBlockLife plugin;
    private final Map<UUID, String> playerSkinData = new ConcurrentHashMap<>();
    private final Map<UUID, Integer> playerCustomModelData = new ConcurrentHashMap<>();
    private final Map<UUID, Long> skinLoadTime = new ConcurrentHashMap<>();
    private final File skinDataFile;
    private final File skinCacheDir;
    private int nextCustomModelData = 1000;
    private static final long SKIN_CACHE_TIME = 7 * 24 * 60 * 60 * 1000L;

    public SkinManager(PlayerBlockLife plugin) {
        this.plugin = plugin;
        this.skinDataFile = new File(plugin.getDataFolder(), "skindata.yml");
        this.skinCacheDir = new File(plugin.getDataFolder(), "skincache");

        if (!skinCacheDir.exists()) {
            skinCacheDir.mkdirs();
        }
    }

    public void loadAllSkins() {
        loadSkinDataFromFile();
        Bukkit.getOnlinePlayers().forEach(this::loadPlayerSkinAsync);
    }

    public void loadPlayerSkinAsync(Player player) {
        UUID playerId = player.getUniqueId();

        if (playerSkinData.containsKey(playerId)) {
            return;
        }

        if (loadSkinFromCache(playerId)) {
            plugin.logInfo("从缓存加载皮肤: " + player.getName());
            return;
        }

        Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
            try {
                plugin.logInfo("开始加载皮肤: " + player.getName());

                String skinBase64 = null;
                String skinSource = "skinsrestorer"; // 使用默认值，因为配置已移除
                
                // 根据配置的皮肤来源优先级获取皮肤
                if ("skinsrestorer".equalsIgnoreCase(skinSource)) {
                    // 优先尝试SkinsRestorer
                    skinBase64 = getSkinFromSkinsRestorer(player);
                    if (skinBase64 == null) {
                        plugin.logInfo("SkinsRestorer获取失败，尝试PlayerProfile: " + player.getName());
                        skinBase64 = getSkinFromPlayerProfile(player);
                    }
                } else if ("player_profile".equalsIgnoreCase(skinSource)) {
                    // 优先尝试PlayerProfile
                    skinBase64 = getSkinFromPlayerProfile(player);
                    if (skinBase64 == null && true) {
                        plugin.logInfo("PlayerProfile获取失败，尝试SkinsRestorer: " + player.getName());
                        skinBase64 = getSkinFromSkinsRestorer(player);
                    }
                } else if ("local_cache".equalsIgnoreCase(skinSource)) {
                    // 优先从本地缓存加载
                    if (loadSkinFromCache(playerId)) {
                        plugin.logInfo("从缓存加载皮肤: " + player.getName());
                        return;
                    }
                    // 缓存不存在，尝试其他来源
                    skinBase64 = getSkinFromPlayerProfile(player);
                    if (skinBase64 == null && true) {
                        skinBase64 = getSkinFromSkinsRestorer(player);
                    }
                }
                
                // 如果所有来源都失败，使用默认Steve皮肤
                if (skinBase64 == null) {
                    skinBase64 = getDefaultSteveSkin();
                    plugin.logWarning("所有皮肤来源都失败，使用默认Steve皮肤: " + player.getName());
                }

                if (skinBase64 != null) {
                    playerSkinData.put(playerId, skinBase64);
                    int modelData = allocateCustomModelData(playerId);
                    saveSkinToCache(playerId, skinBase64);
                    skinLoadTime.put(playerId, System.currentTimeMillis());

                    plugin.logInfo("皮肤加载完成: " + player.getName() + " (模型数据: " + modelData + ")");

                    Bukkit.getScheduler().runTask(plugin, () -> {
                        if (player.isOnline()) {
                            player.sendMessage("§a你的皮肤方块已准备就绪！");
                        }
                    });
                }
            } catch (Exception e) {
                plugin.logError("加载皮肤失败: " + player.getName(), e);
            }
        });
    }

    /**
     * 从SkinsRestorer插件获取玩家皮肤纹理数据
     * 
     * <p>SkinsRestorer是一个流行的皮肤管理插件，可以在离线服务器上提供皮肤支持。</p>
     * 
     * <p>此方法使用反射安全调用SkinsRestorer API，避免硬依赖。支持离线服务器获取玩家自定义皮肤。</p>
     * 
     * <p>获取流程：
     * <ol>
     *   <li>检查SkinsRestorer插件是否安装</li>
     *   <li>使用反射获取SkinsRestorer API实例</li>
     *   <li>优先通过UUID获取皮肤数据（更可靠）</li>
     *   <li>如果UUID获取失败，回退到使用玩家名获取</li>
     *   <li>提取皮肤纹理的value和signature字段</li>
     *   <li>构建完整的Base64编码纹理JSON</li>
     * </ol>
     * </p>
     * 
     * <p><b>离线服务器优势：</b>
     * <ul>
     *   <li>即使玩家离线也能获取其预设皮肤</li>
     *   <li>避免总是显示默认Steve皮肤的问题</li>
     *   <li>支持管理员设置的皮肤和玩家自定义皮肤</li>
     * </ul>
     * </p>
     * 
     * @param player 要获取皮肤的玩家对象
     * @return 完整的Base64编码皮肤纹理JSON，如果获取失败返回null
     * @throws ClassNotFoundException 如果SkinsRestorer API类未找到（插件未安装）
     * @throws Exception 反射调用过程中的其他异常
     */
    private String getSkinFromSkinsRestorer(Player player) {
        try {
            // 检查SkinsRestorer插件是否存在
            if (Bukkit.getPluginManager().getPlugin("SkinsRestorer") == null) {
                plugin.logInfo("SkinsRestorer插件未安装，跳过从SkinsRestorer获取皮肤");
                return null;
            }
            
            plugin.logInfo("尝试从SkinsRestorer获取皮肤: " + player.getName());
            
            // 使用反射调用SkinsRestorer API
            Class<?> skinsRestorerClass = Class.forName("net.skinsrestorer.api.SkinsRestorerAPI");
            Object skinsRestorerAPI = skinsRestorerClass.getMethod("getApi").invoke(null);
            
            // 获取玩家皮肤数据 - 使用UUID而不是玩家名，更可靠
            Class<?> skinPropertyClass = Class.forName("net.skinsrestorer.api.property.SkinProperty");
            Object skinProperty = skinsRestorerAPI.getClass().getMethod("getSkinData", UUID.class)
                    .invoke(skinsRestorerAPI, player.getUniqueId());
            
            // 如果通过UUID获取失败，尝试使用玩家名
            if (skinProperty == null) {
                skinProperty = skinsRestorerAPI.getClass().getMethod("getSkinData", String.class)
                        .invoke(skinsRestorerAPI, player.getName());
            }
            
            if (skinProperty != null) {
                String value = (String) skinPropertyClass.getMethod("getValue").invoke(skinProperty);
                String signature = (String) skinPropertyClass.getMethod("getSignature").invoke(skinProperty);
                
                // 创建完整的纹理JSON对象
                JsonObject textureJson = new JsonObject();
                JsonObject texturesJson = new JsonObject();
                JsonObject skinJson = new JsonObject();
                
                skinJson.addProperty("url", "http://textures.minecraft.net/texture/" + value);
                texturesJson.add("SKIN", skinJson);
                textureJson.add("textures", texturesJson);
                
                // 添加时间戳确保唯一性
                textureJson.addProperty("timestamp", System.currentTimeMillis());
                
                String base64Texture = java.util.Base64.getEncoder().encodeToString(textureJson.toString().getBytes());
                
                plugin.logInfo("成功从SkinsRestorer获取皮肤: " + player.getName());
                return base64Texture;
            } else {
                plugin.logInfo("SkinsRestorer中没有找到玩家 " + player.getName() + " 的皮肤数据");
            }
        } catch (ClassNotFoundException e) {
            plugin.logWarning("SkinsRestorer API类未找到，插件可能未安装或版本不兼容: " + e.getMessage());
        } catch (NoSuchMethodException e) {
            plugin.logWarning("SkinsRestorer API方法未找到，可能是版本不兼容: " + e.getMessage());
        } catch (Exception e) {
            plugin.logWarning("从SkinsRestorer获取皮肤失败: " + e.getMessage());
        }
        
        return null;
    }

    /**
     * 从PlayerProfile获取玩家皮肤数据
     * 
     * <p>使用Bukkit的PlayerProfile API获取在线玩家的皮肤URL，然后转换为Base64纹理。</p>
     * 
     * @param player 要获取皮肤的玩家
     * @return 皮肤的Base64纹理值，如果获取失败返回null
     */
    private String getSkinFromPlayerProfile(Player player) {
        try {
            PlayerProfile profile = player.getPlayerProfile();
            PlayerTextures textures = profile.getTextures();
            URL skinUrl = textures.getSkin();

            if (skinUrl != null) {
                // 创建纹理JSON对象
                JsonObject textureJson = new JsonObject();
                JsonObject texturesJson = new JsonObject();
                JsonObject skinJson = new JsonObject();
                
                // 直接使用皮肤URL，不需要处理图像
                skinJson.addProperty("url", skinUrl.toString());
                texturesJson.add("SKIN", skinJson);
                textureJson.add("textures", texturesJson);
                
                // 添加时间戳确保唯一性
                textureJson.addProperty("timestamp", System.currentTimeMillis());
                textureJson.addProperty("profileId", player.getUniqueId().toString());
                textureJson.addProperty("profileName", player.getName());
                
                String base64Texture = java.util.Base64.getEncoder().encodeToString(textureJson.toString().getBytes());
                
                plugin.logInfo("成功从PlayerProfile获取皮肤: " + player.getName());
                return base64Texture;
            } else {
                plugin.logInfo("PlayerProfile中没有找到玩家 " + player.getName() + " 的皮肤URL");
            }
        } catch (Exception e) {
            plugin.logWarning("从PlayerProfile获取皮肤失败: " + e.getMessage());
        }

        return null;
    }

    private boolean loadSkinFromCache(UUID playerId) {
        try {
            File cacheFile = new File(skinCacheDir, playerId.toString() + ".cache");
            if (cacheFile.exists()) {
                long lastModified = cacheFile.lastModified();
                if (System.currentTimeMillis() - lastModified < SKIN_CACHE_TIME) {
                    String skinData = new String(Files.readAllBytes(cacheFile.toPath()));
                    playerSkinData.put(playerId, skinData);
                    allocateCustomModelData(playerId);
                    return true;
                }
            }
        } catch (Exception e) {
            plugin.logWarning("读取皮肤缓存失败: " + e.getMessage());
        }
        return false;
    }

    private void saveSkinToCache(UUID playerId, String skinData) {
        try {
            File cacheFile = new File(skinCacheDir, playerId.toString() + ".cache");
            Files.write(cacheFile.toPath(), skinData.getBytes());
        } catch (Exception e) {
            plugin.logWarning("保存皮肤缓存失败: " + e.getMessage());
        }
    }

    private synchronized int allocateCustomModelData(UUID playerId) {
        if (playerCustomModelData.containsKey(playerId)) {
            return playerCustomModelData.get(playerId);
        }

        int modelData = nextCustomModelData++;
        playerCustomModelData.put(playerId, modelData);
        return modelData;
    }

    /**
     * 获取默认Steve皮肤的Base64纹理
     * 
     * <p>当无法从任何来源获取玩家皮肤时，使用默认的Steve皮肤作为备用。</p>
     * 
     * @return 默认Steve皮肤的Base64纹理值
     */
    private String getDefaultSteveSkin() {
        // Steve皮肤的纹理哈希值
        String steveTextureHash = "8667ba71b85a4004af54457a9734eed7";
        
        JsonObject textureJson = new JsonObject();
        JsonObject texturesJson = new JsonObject();
        JsonObject skinJson = new JsonObject();
        
        // 使用Minecraft官方纹理服务器URL
        skinJson.addProperty("url", "http://textures.minecraft.net/texture/" + steveTextureHash);
        texturesJson.add("SKIN", skinJson);
        textureJson.add("textures", texturesJson);
        
        // 添加时间戳
        textureJson.addProperty("timestamp", System.currentTimeMillis());
        textureJson.addProperty("profileId", "c06f8906-4c8a-4911-9c29-ea1dbd1aab82"); // Steve的UUID
        textureJson.addProperty("profileName", "Steve");
        
        return java.util.Base64.getEncoder().encodeToString(textureJson.toString().getBytes());
    }

    /**
     * 创建带有玩家皮肤的头颅物品
     * 
     * <p>使用Base64纹理数据创建自定义玩家头颅，支持离线服务器皮肤显示。</p>
     * 
     * @param playerId 玩家UUID
     * @param playerName 玩家名称
     * @return 带有玩家皮肤的玩家头颅物品
     */
    public ItemStack createPlayerHead(UUID playerId, String playerName) {
        ItemStack head = new ItemStack(org.bukkit.Material.PLAYER_HEAD);
        SkullMeta meta = (SkullMeta) head.getItemMeta();

        if (meta != null) {
            // 获取玩家的Base64皮肤数据
            String skinBase64 = playerSkinData.get(playerId);
            
            if (skinBase64 != null) {
                try {
                    // 对于Paper API，我们需要使用Paper特定的方法
                    // 首先尝试使用Paper的ProfileProperty API
                    Class<?> propertyClass = Class.forName("com.destroystokyo.paper.profile.ProfileProperty");
                    
                    // 创建ProfileProperty对象
                    Object property = propertyClass.getConstructor(String.class, String.class)
                            .newInstance("textures", skinBase64);
                    
                    // 获取Paper的PlayerProfile
                    Object profile = Bukkit.class.getMethod("createProfile", UUID.class, String.class)
                            .invoke(null, playerId, playerName);
                    
                    // 设置属性到档案
                    Class<?> profileClass = profile.getClass();
                    profileClass.getMethod("setProperty", propertyClass).invoke(profile, property);
                    
                    // 设置头颅的所有者档案 - 使用正确的类型转换
                    // Paper的SkullMeta.setPlayerProfile期望com.destroystokyo.paper.profile.PlayerProfile
                    meta.setPlayerProfile((com.destroystokyo.paper.profile.PlayerProfile) profile);
                    
                } catch (Exception e) {
                    // 如果反射失败，回退到使用离线玩家（可能显示默认皮肤）
                    plugin.logWarning("无法设置Base64皮肤，使用离线玩家档案: " + e.getMessage());
                    OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerId);
                    meta.setOwningPlayer(offlinePlayer);
                }
            } else {
                // 没有皮肤数据，使用离线玩家
                OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerId);
                meta.setOwningPlayer(offlinePlayer);
            }

            // 设置自定义模型数据（如果有）
            Integer customModelData = playerCustomModelData.get(playerId);
            if (customModelData != null) {
                meta.setCustomModelData(customModelData);
            }

            // 设置显示名称和描述
            meta.setDisplayName("§e" + playerName + "的生命方块");

            List<String> lore = new ArrayList<>();
            lore.add("§7所有者: §e" + playerName);
            lore.add("§c⚠ 警告: 挖掘此方块将减少玩家生命值");
            lore.add("§7剩余生命: §a" + plugin.getBlockManager().getRemainingBlocks(playerId) + "/5");
            meta.setLore(lore);

            head.setItemMeta(meta);
        }

        return head;
    }

    public boolean isSkinLoaded(UUID playerId) {
        return playerSkinData.containsKey(playerId);
    }

    public Integer getCustomModelData(UUID playerId) {
        return playerCustomModelData.get(playerId);
    }

    public Map<UUID, String> getAllSkinData() {
        return new HashMap<>(playerSkinData);
    }

    public Map<UUID, Integer> getAllCustomModelData() {
        return new HashMap<>(playerCustomModelData);
    }

    private void loadSkinDataFromFile() {
        if (!skinDataFile.exists()) {
            return;
        }

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

            if (data != null && data.containsKey("skins")) {
                Map<String, Object> skins = (Map<String, Object>) data.get("skins");
                for (Map.Entry<String, Object> entry : skins.entrySet()) {
                    UUID playerId = UUID.fromString(entry.getKey());
                    String skinData = (String) entry.getValue();
                    playerSkinData.put(playerId, skinData);
                }
            }

            if (data != null && data.containsKey("modelData")) {
                Map<String, Integer> modelData = (Map<String, Integer>) data.get("modelData");
                for (Map.Entry<String, Integer> entry : modelData.entrySet()) {
                    UUID playerId = UUID.fromString(entry.getKey());
                    playerCustomModelData.put(playerId, entry.getValue());
                    nextCustomModelData = Math.max(nextCustomModelData, entry.getValue() + 1);
                }
            }

            plugin.logInfo("已加载 " + playerSkinData.size() + " 个玩家的皮肤数据");
        } catch (Exception e) {
            plugin.logError("加载皮肤数据文件失败", e);
        }
    }

    public void saveSkinData() {
        try {
            Map<String, Object> data = new HashMap<>();

            Map<String, String> skins = new HashMap<>();
            for (Map.Entry<UUID, String> entry : playerSkinData.entrySet()) {
                skins.put(entry.getKey().toString(), entry.getValue());
            }
            data.put("skins", skins);

            Map<String, Integer> modelData = new HashMap<>();
            for (Map.Entry<UUID, Integer> entry : playerCustomModelData.entrySet()) {
                modelData.put(entry.getKey().toString(), entry.getValue());
            }
            data.put("modelData", modelData);

            Yaml yaml = new Yaml();
            yaml.dump(data, new FileWriter(skinDataFile));

            plugin.logInfo("皮肤数据已保存");
        } catch (Exception e) {
            plugin.logError("保存皮肤数据失败", e);
        }
    }

    public void cleanupOldCache() {
        File[] cacheFiles = skinCacheDir.listFiles();
        if (cacheFiles != null) {
            long now = System.currentTimeMillis();
            int cleaned = 0;

            for (File file : cacheFiles) {
                if (now - file.lastModified() > SKIN_CACHE_TIME) {
                    if (file.delete()) {
                        cleaned++;
                    }
                }
            }

            if (cleaned > 0) {
                plugin.logInfo("清理了 " + cleaned + " 个过期皮肤缓存");
            }
        }
    }
}