package fr.luc.gamingcore.worldguard;

import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import fr.luc.gamingcore.Main;
import fr.luc.gamingcore.model.Guild;
import fr.luc.gamingcore.model.GuildClaim;
import fr.luc.gamingcore.model.GuildMember;
import org.bukkit.Bukkit;
import org.bukkit.World;

import java.util.Collection;
import java.util.Objects;
import java.util.logging.Level;

/**
 * Service d'intégration avec WorldGuard 7 pour la création, la protection et la synchronisation des régions de claim.
 */
public class WorldGuardManager {

    private final Main plugin;
    private final RegionContainer regionContainer;
    private final boolean enabled;

    /**
     * Constructeur du WorldGuardManager.
     *
     * @param plugin L'instance principale de GamingCore.
     */
    public WorldGuardManager(Main plugin) {
        this.plugin = Objects.requireNonNull(plugin, "plugin cannot be null");
        RegionContainer container = null;
        boolean isEnabled = false;

        try {
            if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null) {
                container = WorldGuard.getInstance().getPlatform().getRegionContainer();
                isEnabled = (container != null);
            }
        } catch (Throwable t) {
            plugin.getLogger().log(Level.WARNING, "Erreur lors de l'initialisation de WorldGuardManager : " + t.getMessage());
        }

        this.regionContainer = container;
        this.enabled = isEnabled;
    }

    /**
     * Indique si l'intégration WorldGuard est active.
     *
     * @return true si WorldGuard est chargé et fonctionnel.
     */
    public boolean isEnabled() {
        return enabled && regionContainer != null;
    }

    /**
     * Génère l'identifiant unique WorldGuard d'une région de claim pour un chunk donné.
     *
     * @param guild  La guilde propriétaire.
     * @param chunkX Coordonnée X du chunk.
     * @param chunkZ Coordonnée Z du chunk.
     * @return L'identifiant normalisé de la région (ex: "guild_a1b2c3d4_12_-4").
     */
    public String getRegionId(Guild guild, int chunkX, int chunkZ) {
        String cleanId = guild.getId().toString().replace("-", "").substring(0, 12);
        return "guild_" + cleanId + "_" + chunkX + "_" + chunkZ;
    }

    /**
     * Obtient le gestionnaire de régions WorldGuard pour un monde Bukkit donné.
     *
     * @param world Le monde Bukkit.
     * @return L'instance RegionManager ou null si indisponible.
     */
    public RegionManager getRegionManager(World world) {
        if (!isEnabled() || world == null) return null;
        return regionContainer.get(BukkitAdapter.adapt(world));
    }

    /**
     * Crée ou met à jour la région WorldGuard associée à un claim territorial de guilde.
     * Les membres de la guilde sont enregistrés en tant que membres de la région (permettant la pose/casse de blocs et l'ouverture de coffres).
     *
     * @param guild  La guilde propriétaire.
     * @param world  Le monde Bukkit dans lequel se situe le claim.
     * @param chunkX Coordonnée X du chunk.
     * @param chunkZ Coordonnée Z du chunk.
     * @return La région protégée créée ou mise à jour, ou null en cas d'échec.
     */
    public ProtectedRegion createOrUpdateRegion(Guild guild, World world, int chunkX, int chunkZ) {
        if (!isEnabled() || guild == null || world == null) return null;

        RegionManager regionManager = getRegionManager(world);
        if (regionManager == null) return null;

        String regionId = getRegionId(guild, chunkX, chunkZ);
        ProtectedRegion region = regionManager.getRegion(regionId);

        int minX = chunkX * 16;
        int minZ = chunkZ * 16;
        int maxX = minX + 15;
        int maxZ = minZ + 15;
        int minY = world.getMinHeight();
        int maxY = world.getMaxHeight() - 1;

        BlockVector3 min = BlockVector3.at(minX, minY, minZ);
        BlockVector3 max = BlockVector3.at(maxX, maxY, maxZ);

        if (region == null) {
            region = new ProtectedCuboidRegion(regionId, min, max);
            region.setPriority(plugin.getConfig().getInt("worldguard.region_priority", 10));

            // Flags WorldGuard
            region.setFlag(Flags.PASSTHROUGH, StateFlag.State.DENY);
            region.setFlag(Flags.TNT, StateFlag.State.DENY);
            region.setFlag(Flags.CREEPER_EXPLOSION, StateFlag.State.DENY);
            region.setFlag(Flags.PVP, StateFlag.State.DENY);
            region.setFlag(Flags.PISTONS, StateFlag.State.ALLOW);
            region.setFlag(Flags.FIRE_SPREAD, StateFlag.State.DENY);
            region.setFlag(Flags.LAVA_FIRE, StateFlag.State.DENY);
            region.setFlag(Flags.LIGHTER, StateFlag.State.DENY);

            regionManager.addRegion(region);
        }

        // Synchroniser les membres et propriétaires
        syncRegionMembers(guild, region);

        return region;
    }

    /**
     * Supprime la région WorldGuard correspondant à un chunk précis.
     *
     * @param guild  La guilde propriétaire.
     * @param world  Le monde du chunk.
     * @param chunkX Coordonnée X.
     * @param chunkZ Coordonnée Z.
     * @return true si la région a été supprimée.
     */
    public boolean removeRegion(Guild guild, World world, int chunkX, int chunkZ) {
        if (!isEnabled() || guild == null || world == null) return false;

        RegionManager regionManager = getRegionManager(world);
        if (regionManager == null) return false;

        String regionId = getRegionId(guild, chunkX, chunkZ);
        return regionManager.removeRegion(regionId) != null;
    }

    /**
     * Supprime toutes les régions WorldGuard appartenant à une guilde dans tous les mondes (utilisé lors du disband).
     *
     * @param guild La guilde dissoute.
     */
    public void removeGuildRegions(Guild guild) {
        if (!isEnabled() || guild == null) return;

        for (GuildClaim claim : guild.getClaims()) {
            World world = Bukkit.getWorld(claim.getWorldName());
            if (world != null) {
                removeRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
            }
        }
    }

    /**
     * Synchronise la liste des membres et propriétaires sur toutes les régions WorldGuard d'une guilde.
     * Doit être appelée à chaque ajout, retrait ou modification de membre.
     *
     * @param guild La guilde à synchroniser.
     */
    public void syncGuildMembers(Guild guild) {
        if (!isEnabled() || guild == null) return;

        for (GuildClaim claim : guild.getClaims()) {
            World world = Bukkit.getWorld(claim.getWorldName());
            if (world == null) continue;

            RegionManager regionManager = getRegionManager(world);
            if (regionManager == null) continue;

            String regionId = getRegionId(guild, claim.getChunkX(), claim.getChunkZ());
            ProtectedRegion region = regionManager.getRegion(regionId);

            if (region == null) {
                // Si la région n'existe pas encore, la créer
                createOrUpdateRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
            } else {
                syncRegionMembers(guild, region);
            }
        }
    }

    /**
     * Synchronise tous les claims et membres de l'intégralité des guildes dans WorldGuard au démarrage du serveur.
     *
     * @param guilds Collection des guildes chargées en mémoire.
     */
    public void syncAllGuilds(Collection<Guild> guilds) {
        if (!isEnabled() || guilds == null) return;

        int totalRegions = 0;
        for (Guild guild : guilds) {
            for (GuildClaim claim : guild.getClaims()) {
                World world = Bukkit.getWorld(claim.getWorldName());
                if (world != null) {
                    createOrUpdateRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
                    totalRegions++;
                }
            }
        }

        plugin.getLogger().info("WorldGuard: Synchronisation de " + totalRegions + " regions territoriales de guilde terminee avec succes !");
    }

    /**
     * Met à jour les domaines de membres et d'owners d'une région WorldGuard à partir de la guilde.
     *
     * @param guild  La guilde source.
     * @param region La région WorldGuard cible.
     */
    private void syncRegionMembers(Guild guild, ProtectedRegion region) {
        // 1. Mise à jour des propriétaires (Chef de guilde)
        region.getOwners().clear();
        GuildMember leader = guild.getLeaderMember();
        if (leader != null) {
            region.getOwners().addPlayer(leader.getPlayerUuid());
        }

        // 2. Mise à jour des membres (Tous les membres de la guilde)
        region.getMembers().clear();
        for (GuildMember member : guild.getMembers()) {
            region.getMembers().addPlayer(member.getPlayerUuid());
        }
    }
}
