/*
 *   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.bausystem.features.world;

import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.flags.ColorMode;
import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.linkage.Linked;
import de.steamwar.scoreboard.SWScoreboard;
import de.steamwar.scoreboard.ScoreboardCallback;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
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 java.util.*;

@Linked
public class BauScoreboard implements Listener {

    @Setter
    @Getter
    @AllArgsConstructor
    public static class Data {
        private ScoreboardElement.ScoreboardGroup group;
        private Integer priority;
        private String text;
    }

    private static final Map<ScoreboardElement.ScoreboardGroup, List<ScoreboardElement>> ELEMENTS = new HashMap<>();
    private static final Map<Player, Map<String, Data>> ADDITIONAL_SCOREBOARD_LINES = new HashMap<>();

    public static void addElement(ScoreboardElement scoreboardElement) {
        List<ScoreboardElement> elements = ELEMENTS.computeIfAbsent(scoreboardElement.getGroup(), scoreboardGroup -> new ArrayList<>());
        elements.add(scoreboardElement);
        elements.sort(Comparator.comparingInt(ScoreboardElement::order));
    }

    public static void setAdditionalElement(Player player, String key, ScoreboardElement.ScoreboardGroup group, int priority, String value) {
        Map<String, Data> playerElements = ADDITIONAL_SCOREBOARD_LINES.computeIfAbsent(player, player1 -> new HashMap<>());
        if (value == null || value.isBlank()) {
            playerElements.remove(key);
            return;
        }
        Data element = playerElements.computeIfAbsent(key, s -> new Data(null, null, null));
        element.setGroup(group);
        element.setPriority(priority);
        element.setText(value);
    }

    @EventHandler
    public void handlePlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();

        SWScoreboard.impl.createScoreboard(player, new ScoreboardCallback() {
            @Override
            public HashMap<String, Integer> getData() {
                Region region = Region.getRegion(player.getLocation());

                List<String> elements = new ArrayList<>();
                calcGroup(elements, null, region, ScoreboardElement.ScoreboardGroup.HEADER);
                calcGroup(elements, "§1", region, ScoreboardElement.ScoreboardGroup.REGION);
                calcGroup(elements, "§2", region, ScoreboardElement.ScoreboardGroup.OTHER);
                calcGroup(elements, "§3", region, ScoreboardElement.ScoreboardGroup.FOOTER);

                int i = elements.size();
                HashMap<String, Integer> result = new HashMap<>();
                for (String s : elements) {
                    result.put(s, i--);
                }
                return result;
            }

            private void calcGroup(List<String> elements, String separator, Region region, ScoreboardElement.ScoreboardGroup group) {
                List<String> groupElements = new ArrayList<>();
                if (ELEMENTS.containsKey(group)) {
                    for (ScoreboardElement element : ELEMENTS.get(group)) {
                        groupElements.add(element.get(region, player));
                    }
                }
                if (ADDITIONAL_SCOREBOARD_LINES.containsKey(player)) {
                    ADDITIONAL_SCOREBOARD_LINES.get(player).values()
                            .stream()
                            .filter(triple -> triple.getGroup() == group)
                            .sorted(Comparator.comparing(Data::getPriority))
                            .forEach(triple -> {
                                groupElements.add(triple.getText());
                            });
                }
                groupElements.removeIf(Objects::isNull);
                if (!groupElements.isEmpty()) {
                    if (separator != null) elements.add(separator);
                    elements.addAll(groupElements);
                }
            }

            @Override
            public String getTitle() {
                Region region = Region.getRegion(player.getLocation());
                if (region.getType().isGlobal()) return "§eSteam§8War";
                String colorCode = "§e";
                if (region.getRegionData().has(Flag.COLOR).isReadable()) {
                    colorCode = "§" + region.getRegionData().get(Flag.COLOR).orElse(ColorMode.PINK).getColorCode();
                }
                return colorCode + "■ §eSteam§8War " + colorCode + "■"; // ■
            }
        });
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        ADDITIONAL_SCOREBOARD_LINES.remove(event.getPlayer());
    }
}
