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

import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.ai.AIManager;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.ClickEvent;
import org.bukkit.entity.Player;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class JoinRequest {

    private static final Map<Player, JoinRequest> playerRequests = new HashMap<>();
    private static final List<JoinRequest> activeRequests = new ArrayList<>();

    public static JoinRequest get(Player player) {
        return playerRequests.get(player);
    }

    public static List<SWListInv.SWListEntry<JoinRequest>> openRequests(Player p, FightTeam team) {
        return activeRequests.stream().filter(
                request -> request.waitOnApproval.contains(team)
        ).map(request -> {
            AtomicReference<SWItem> item = new AtomicReference<>();
            request.enquirer.ifPlayer(player -> item.set(SWItem.getPlayerSkull(player)));
            request.enquirer.ifAI(manager -> item.set(new SWItem(manager.getIcon(), manager.name())));
            item.get().setLore(Arrays.asList(
                    FightSystem.getMessage().parse("REQUESTS_LEFT_CLICK", p),
                    FightSystem.getMessage().parse("REQUESTS_RIGHT_CLICK", p)
            ));
            return new SWListInv.SWListEntry<>(item.get(), request);
        }).collect(Collectors.toList());
    }

    public static void clearRequests() {
        playerRequests.clear();
        activeRequests.clear();
    }

    public static void forPlayer(Player player, FightTeam team) {
        new JoinRequest(new Enquirer() {
            @Override
            public String name() {
                return player.getName();
            }

            @Override
            public void ifPlayer(Consumer<Player> function) {
                function.accept(player);
            }

            @Override
            public void ifAI(Consumer<AIManager> function) {
            }
        }, team, FightState.ingame() ? Fight.teams() : Collections.singleton(team));
    }

    public static void forAI(AIManager manager, FightTeam team) {
        new JoinRequest(new Enquirer() {
            @Override
            public String name() {
                return manager.name();
            }

            @Override
            public void ifPlayer(Consumer<Player> function) {
            }

            @Override
            public void ifAI(Consumer<AIManager> function) {
                function.accept(manager);
            }
        }, team, Collections.singleton(Fight.getOpposite(team)));
    }

    private final Enquirer enquirer;
    private final FightTeam team;
    private final Set<FightTeam> waitOnApproval;

    private JoinRequest(Enquirer enquirer, FightTeam team, Collection<FightTeam> waitOnApproval) {
        this.enquirer = enquirer;
        this.team = team;
        this.waitOnApproval = new HashSet<>(waitOnApproval);
        Set<FightTeam> alreadyAccepted = new HashSet<>();

        enquirer.ifPlayer(player -> playerRequests.put(player, this));
        activeRequests.add(this);
        for (FightTeam t : waitOnApproval) {
            FightPlayer leader = t.getLeader();
            if (leader == null) continue;

            if (leader.getEntity() == null) continue;

            leader.ifPlayer(leaderPlayer -> FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_NOTIFICATION", leaderPlayer, "REQUESTS", new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/requests"), enquirer.name(), team.getColoredName()));
            leader.ifAI(ai -> {
                if (ai.acceptJoinRequest(enquirer, team)) {
                    alreadyAccepted.add(t);
                }
            });
        }

        enquirer.ifPlayer(player -> FightSystem.getMessage().sendPrefixless("JOIN_REQUEST_CONFIRMATION", player, ChatMessageType.ACTION_BAR));
        alreadyAccepted.forEach(this::accept);
    }

    public boolean required(FightTeam decider) {
        return waitOnApproval.contains(decider);
    }

    public void accept(FightTeam acceptor) {
        waitOnApproval.remove(acceptor);

        if (waitOnApproval.isEmpty()) {
            enquirer.ifPlayer(team::addMember);
            enquirer.ifAI(manager -> manager.join(team));
            close();
        }
    }

    public void decline(FightTeam declinor) {
        enquirer.ifPlayer(player -> FightSystem.getMessage().sendPrefixless("REQUEST_YOUR_DECLINED", player, ChatMessageType.ACTION_BAR));
        waitOnApproval.forEach(t -> t.broadcast("REQUEST_DECLINED", enquirer.name()));
        close();
    }

    public void close() {
        enquirer.ifPlayer(playerRequests::remove);
        activeRequests.remove(this);
    }

    public interface Enquirer {
        String name();

        void ifPlayer(Consumer<Player> function);

        void ifAI(Consumer<AIManager> function);
    }
}
