/*
 *   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.misslewars;

import lombok.Getter;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scoreboard.Team;

import java.util.*;

public class MWTeam {
    public static final ItemStack bow = new ItemStack(Material.BOW);

    static {
        ItemMeta bowMeta = Objects.requireNonNull(bow.getItemMeta());
        bowMeta.addEnchant(Enchantment.FLAME, 1, true);
        bowMeta.addEnchant(Enchantment.PUNCH, 1, true);
        bowMeta.addEnchant(Enchantment.KNOCKBACK, 1, true);
        bowMeta.addEnchant(Enchantment.POWER, 2, true);
        bowMeta.setUnbreakable(true);
        bow.setItemMeta(bowMeta);
    }

    private final String color;
    private final String teamName;
    private final Team sbteam; //scoreboard-Team
    @Getter
    private final Location spawn;
    @Getter
    private final int portalZ;

    @Getter
    private final LinkedList<Player> players = new LinkedList<>();
    private final Set<Player> openInvitations = new HashSet<>();

    MWTeam(String color, Location spawn, String teamName, int portalZ) {
        this.teamName = teamName;
        this.color = color;
        this.spawn = spawn;
        this.portalZ = portalZ;
        if (FightScoreboard.getScoreboard().getTeam(teamName) == null) {
            sbteam = FightScoreboard.getScoreboard().registerNewTeam(teamName);
        } else {
            sbteam = FightScoreboard.getScoreboard().getTeam(teamName);
        }
        assert sbteam != null;
        sbteam.setAllowFriendlyFire(false);
        sbteam.setColor(ChatColor.getByChar(color.charAt(1)));
    }

    public void countdown(int timeDelay, int offset) {
        if (players.isEmpty()) {
            return;
        }

        int i = 0;
        for (Player p : players) {
            int time = timeDelay * (i + 1) - offset;
            i++;

            p.setExp(time / (float) Config.ItemTime);
            p.setLevel(0);
        }
    }

    private int getUsesOfItem(ItemStack itemStack) {
        ItemMeta itemMeta = itemStack.getItemMeta();
        if (itemMeta instanceof Damageable) {
            Damageable damageable = (Damageable) itemMeta;
            return itemStack.getType().getMaxDurability() - damageable.getDamage();
        }
        return 1_000_000;
    }

    private boolean hasUses(ItemStack itemStack) {
        switch (itemStack.getType()) {
            case WOODEN_AXE:
            case STONE_AXE:
            case IRON_AXE:
            case GOLDEN_AXE:
            case DIAMOND_AXE:
            case NETHERITE_AXE:
                // return true;
            case WOODEN_SHOVEL:
            case STONE_SHOVEL:
            case IRON_SHOVEL:
            case GOLDEN_SHOVEL:
            case DIAMOND_SHOVEL:
            case NETHERITE_SHOVEL:
                // return true;
            case WOODEN_PICKAXE:
            case STONE_PICKAXE:
            case IRON_PICKAXE:
            case GOLDEN_PICKAXE:
            case DIAMOND_PICKAXE:
            case NETHERITE_PICKAXE:
                return true;
            default:
                return false;
        }
    }

    public void givePlayerItem(ItemStack item) {
        if (players.isEmpty()) {
            return;
        }
        Player p = players.removeFirst();
        players.addLast(p);

        Inventory inventory = p.getInventory();
        for (int i = 0; i <= 35; i++) { // 35 is the last normal inventory slot
            ItemStack itemStack = inventory.getItem(i);
            if (itemStack == null) continue;
            if (itemStack.isSimilar(item) && itemStack.getAmount() + item.getAmount() <= item.getMaxStackSize()) {
                itemStack.setAmount(itemStack.getAmount() + item.getAmount());
                inventory.setItem(i, itemStack);
                return;
            }
            if (hasUses(itemStack) && hasUses(item) && getUsesOfItem(itemStack) + getUsesOfItem(item) <= itemStack.getType().getMaxDurability()) {
                int uses = getUsesOfItem(itemStack) + getUsesOfItem(item);
                ItemMeta itemMeta = itemStack.getItemMeta();
                Damageable damageable = (Damageable) itemMeta;
                damageable.setDamage(itemStack.getType().getMaxDurability() - uses);
                itemStack.setItemMeta(damageable);
                inventory.setItem(i, itemStack);
                return;
            }
        }

        for (int i = 0; i <= 35; i++) { // 35 is the last normal inventory slot
            ItemStack itemStack = inventory.getItem(i);
            if (itemStack == null || itemStack.getType().equals(Material.AIR)) {
                inventory.setItem(i, item);
                return;
            }
        }
    }

    public void teamScoreboard(HashMap<String, Integer> data) {
        players.forEach(player -> {
            data.put(getColorCode() + player.getName(), 1);
        });
    }

    public int size() {
        return players.size();
    }

    public void join(Player p) {
        players.add(p);
        p.teleport(spawn);
        p.setGameMode(GameMode.SURVIVAL);
        p.getInventory().setItem(0, bow);
        sbteam.addPlayer(p);
        p.setDisplayName(color + p.getName());
        if (MissileWars.getFightState() == FightState.WAITING && !enemy().players.isEmpty()) {
            MissileWars.startRound();
        }
    }

    public void leave(Player p) {
        if (!players.contains(p)) return;
        players.remove(p);

        for (ItemStack stack : p.getInventory().getContents()) {
            if (stack == null) continue;
            if (stack.getType() == Material.AIR) continue;
            if (stack.isSimilar(bow)) continue;
            givePlayerItem(stack);
        }

        p.getInventory().clear();

        p.setDisplayName("§7" + p.getName());
        if (players.isEmpty() && MissileWars.getFightState() == FightState.FIGHTING) {
            MissileWars.end(WinReasons.NO_ENEMY, enemy());
        }

        sbteam.removePlayer(p);
    }

    public void reset() {
        openInvitations.clear();

        List<Player> tempPlayer = new ArrayList<>(players);
        players.clear();
        tempPlayer.forEach(player -> player.getInventory().clear());
        tempPlayer.forEach(player -> player.setHealth(20.0));
        tempPlayer.forEach(this::join);
    }

    public void invitePlayer(Player p) {
        if (enemy().openInvitations.contains(p)) return;
        openInvitations.add(p);
    }

    public void acceptInvite(Player p) {
        removeInvitations(p);
        join(p);
    }

    private MWTeam enemy() {
        if (this == MissileWars.getRedTeam()) return MissileWars.getBlueTeam();
        return MissileWars.getRedTeam();
    }

    public String getColorCode() {
        return color;
    }

    public boolean hasPlayer(Player p) {
        return players.contains(p);
    }

    public boolean hasInvite(Player p) {
        return openInvitations.contains(p);
    }

    public String getColoredName() {
        return color + teamName;
    }

    public static void removeInvitations(Player p) {
        MissileWars.getRedTeam().openInvitations.remove(p);
        MissileWars.getBlueTeam().openInvitations.remove(p);
    }
}
