/*
 *   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 org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;

import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.events.BoardingEvent;
import de.steamwar.fightsystem.events.TeamDeathEvent;
import de.steamwar.fightsystem.events.TeamLeaveEvent;
import de.steamwar.fightsystem.events.TeamSpawnEvent;
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.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;

public class TeamArea implements Listener {

    private final FightTeam team;
    private final Border spectatorBorder;
    private final Border bordingBorder;

    public TeamArea(FightTeam team) {
        this.team = team;
        this.spectatorBorder = new Border(team.getExtendRegion(), false, 5, "NO_TEAMAREA", team.getName() + ".spectatorBorder");
        this.bordingBorder = new Border(team.getExtendRegion().to2d(), true, 1, "NO_ENTERN", team.getName() + ".boardingBorder");

        new StateDependentListener(ArenaMode.AntiTest, FightState.All, this);
        new OneShotStateDependent(ArenaMode.AntiTest, FightState.Spectate, () -> Fight.teams().forEach(t -> t.getPlayers().forEach(this::teamSpectator)));
    }

    @EventHandler
    public void playerJoin(PlayerJoinEvent e) {
        Player player = e.getPlayer();
        if(Fight.getPlayerTeam(player) != team && !Config.isReferee(player))
            spectatorBorder.addPlayer(player);
    }

    @EventHandler
    public void teamJoin(TeamSpawnEvent e) {
        FightPlayer fightPlayer = e.getFightPlayer();
        if(fightPlayer.getTeam() == team) {
            fightPlayer.ifPlayer(player -> {
                spectatorBorder.removePlayer(player);
                bordingBorder.addPlayer(player);
            });
        }
    }

    @EventHandler
    public void teamLeave(TeamLeaveEvent e) {
        FightPlayer fightPlayer = e.getFightPlayer();
        fightPlayer.ifPlayer(spectatorBorder::addPlayer);
        if(fightPlayer.getTeam() == team)
            fightPlayer.ifPlayer(bordingBorder::removePlayer);
    }

    @EventHandler
    public void boarding(BoardingEvent e) {
        FightPlayer fightPlayer = e.getFightPlayer();
        if(fightPlayer.getTeam() == team) {
            fightPlayer.ifPlayer(bordingBorder::removePlayer);
        } else {
            fightPlayer.ifPlayer(spectatorBorder::removePlayer);
        }
    }

    @EventHandler
    public void teamDeath(TeamDeathEvent e) {
        teamSpectator(e.getFightPlayer());
    }

    private void teamSpectator(FightPlayer fightPlayer) {
        if(fightPlayer.getTeam() == team) {
            fightPlayer.ifPlayer(bordingBorder::removePlayer);
        } else {
            fightPlayer.ifPlayer(spectatorBorder::addPlayer);
        }
    }

    @EventHandler
    public void playerQuit(PlayerQuitEvent e) {
        Player player = e.getPlayer();
        spectatorBorder.removePlayer(player);
        bordingBorder.removePlayer(player);
    }
}
