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;

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 = getSkinFromPlayerProfile(player);

                if (skinBase64 == null) {
                    skinBase64 = getDefaultSteveSkin();
                    plugin.logWarning("使用默认皮肤: " + 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);
            }
        });
    }

    private String getSkinFromPlayerProfile(Player player) {
        try {
            PlayerProfile profile = player.getPlayerProfile();
            PlayerTextures textures = profile.getTextures();
            URL skinUrl = textures.getSkin();

            if (skinUrl != null) {
                BufferedImage skinImage = ImageIO.read(skinUrl);
                if (skinImage == null) {
                    return null;
                }

                int headX = 8;
                int headY = 8;
                int headWidth = 8;
                int headHeight = 8;

                if (skinImage.getWidth() >= headX + headWidth &&
                        skinImage.getHeight() >= headY + headHeight) {

                    BufferedImage headImage = skinImage.getSubimage(headX, headY, headWidth, headHeight);

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(headImage, "PNG", baos);
                    byte[] imageBytes = baos.toByteArray();

                    JsonObject textureJson = new JsonObject();
                    JsonObject timestampJson = new JsonObject();

                    return player.getUniqueId().toString();
                }
            }
        } 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;
    }

    private String getDefaultSteveSkin() {
        return "8667ba71-b85a-4004-af54-457a9734eed7";
    }

    public ItemStack createPlayerHead(UUID playerId, String playerName) {
        ItemStack head = new ItemStack(org.bukkit.Material.PLAYER_HEAD);
        SkullMeta meta = (SkullMeta) head.getItemMeta();

        if (meta != null) {
            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 + " 个过期皮肤缓存");
            }
        }
    }
}