/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.fightsystem.listener;

import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.BountifulWrapper;
import de.steamwar.fightsystem.utils.FlatteningWrapper;
import de.steamwar.linkage.Linked;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.SpawnerSpawnEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.player.*;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scoreboard.NameTagVisibility;
import org.bukkit.scoreboard.Team;

@Linked
public class Permanent implements Listener {

    private static final Team spectatorTeam = FightScoreboard.getBukkitTeam("Spectator");

    static {
        BountifulWrapper.impl.setNametagVisibility(spectatorTeam);
        spectatorTeam.setNameTagVisibility(NameTagVisibility.NEVER);
    }

    public static Team getSpectatorTeam() {
        return spectatorTeam;
    }

    public Permanent() {
        new StateDependentListener(ArenaMode.All, FightState.All, this);
    }

    @EventHandler
    public void handlePlayerRespawn(PlayerRespawnEvent event) {
        Player player = event.getPlayer();
        if (Fight.fighting(player)) {
            player.setGameMode(GameMode.SPECTATOR);

            FightTeam team = Fight.getPlayerTeam(player);
            event.setRespawnLocation(team == null ? Config.SpecSpawn : team.getSpawn());
        }
    }

    @EventHandler
    public void onTpGM3(PlayerTeleportEvent e) {
        if (ArenaMode.AntiTest.contains(Config.mode) && e.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE) {
            e.setCancelled(true);
            FightSystem.getMessage().sendPrefixless("NO_TELEPORT", e.getPlayer(), ChatMessageType.ACTION_BAR);
            e.getPlayer().kickPlayer(null);
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void handlePlayerJoin(PlayerJoinEvent event) {
        event.setJoinMessage(null);

        Player player = event.getPlayer();
        FightPlayer fp = Fight.getFightPlayer(player);

        if (!Config.GameModeConfig.Arena.Leaveable && fp == null) {
            player.setGameMode(GameMode.SPECTATOR);
            spectatorTeam.addEntry(player.getName());
            player.teleport(Config.SpecSpawn);
        } else if (fp != null && !fp.isLiving()) {
            player.setGameMode(GameMode.SPECTATOR);
            player.teleport(fp.getTeam().getSpawn());
        }
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void handlePlayerDeath(PlayerDeathEvent event) {
        if (!Config.GameModeConfig.Arena.Leaveable || Fight.fighting(event.getEntity())) {
            event.setDeathMessage(null);
        }
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void handlePlayerLeave(PlayerQuitEvent event) {
        if (!Config.GameModeConfig.Arena.Leaveable) {
            event.setQuitMessage(null);
        }
    }

    @EventHandler
    public void handleFoodLevelChange(FoodLevelChangeEvent event) {
        if (Fight.fighting(event.getEntity())) {
            event.setCancelled(true);
        }
    }

    @EventHandler
    public void onWeatherChange(WeatherChangeEvent event) {
        event.setCancelled(true);
    }

    @EventHandler
    public void onSpawnerSpawn(SpawnerSpawnEvent e) {
        if (Config.ArenaRegion.inRegion(e.getSpawner().getBlock())) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void onSleep(PlayerBedEnterEvent e) {
        if (Fight.fighting(e.getPlayer())) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void onCrafting(CraftItemEvent e) {
        if (Fight.fighting(e.getWhoClicked())) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void onFurnace(FurnaceSmeltEvent e) {
        if (Config.ArenaRegion.inRegion(e.getBlock())) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void onDropPickup(PlayerPickupItemEvent e) {
        if (!(Config.ArenaRegion.inRegion(e.getItem().getLocation()))) return;
        Player player = e.getPlayer();

        ItemStack stack = e.getItem().getItemStack();
        if (Config.GameModeConfig.Kits.PersonalKits) {
            if (Config.GameModeConfig.Kits.ForbiddenItems.contains(stack.getType())) {
                e.setCancelled(true);
            }
        } else {
            FightPlayer fp = Fight.getFightPlayer(player);
            if (fp == null) return;

            if (!fp.getKit().contains(stack)) {
                e.setCancelled(true);
            }
        }
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onExplosion(EntityExplodeEvent e) {
        if (!(e.getEntity() instanceof TNTPrimed)) {
            if (Config.GameModeConfig.Schematic.Type.toDB().equals("wargearseason26")) {
                e.blockList().clear();
            }
            return;
        }
        if (!Config.GameModeConfig.Arena.WaterDamage) return;
        e.blockList().removeIf(block -> {
            if (block.getType() == Material.TNT) {
                return false;
            } else {
                block.setType(Material.AIR);
                return true;
            }
        });
    }

    @EventHandler
    public void onWorldLoad(WorldLoadEvent e) {
        if (!Config.GameModeConfig.Arena.Leaveable) {
            e.getWorld().setAutoSave(false);
        }
    }

    @EventHandler
    public void onBlockFromTo(BlockFromToEvent event) {
        if (!event.getBlock().getType().equals(Material.DRAGON_EGG)) return;

        for (FightTeam team : Fight.teams()) {
            if (team.getExtendRegion().inRegion(event.getBlock())) {

                if (team.getExtendRegion().inRegion(event.getToBlock())) return;

            }
        }

        event.setCancelled(true);
    }

    @EventHandler
    public void onBlockDispense(BlockDispenseEvent e) {
        Block block = e.getBlock();

        if (!Config.ArenaRegion.inRegion(block)) {
            return;
        }

        if (e.getItem().getType() == Material.TNT || FlatteningWrapper.impl.isFacingWater(block)) {
            e.setCancelled(true);
        }
    }

    @EventHandler
    public void blockPlace(BlockPlaceEvent event) {
        Player player = event.getPlayer();
        Block block = event.getBlock();
        if (Fight.teams().stream().anyMatch(team -> team.getExtendRegion().inRegion(block))) {
            return;
        }

        event.setCancelled(true);
        FightSystem.getMessage().sendPrefixless("NO_BLOCK_PLACE", player, ChatMessageType.ACTION_BAR);
    }

    @EventHandler
    public void blockBreak(BlockBreakEvent event) {
        Block block = event.getBlock();
        if (Config.BlueExtendRegion.getMinY() <= block.getY()) return;

        event.setCancelled(true);
        FightSystem.getMessage().sendPrefixless("NO_BLOCK_BREAK", event.getPlayer(), ChatMessageType.ACTION_BAR);
    }
}
