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

import de.steamwar.lobby.portal.FightserverPortal;
import de.steamwar.network.packets.common.FightInfoPacket;
import org.bukkit.Bukkit;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Consumer;

public class Fightserver {

    private static final Map<String, Fightserver> servers = new HashMap<>();

    public static void init() {
        Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), Fightserver::removeStopped, 20, 20);
    }

    public static void newFightInfo(FightInfoPacket in) {
        Fightserver server = servers.get(in.getServerName());
        if (server == null) {
            new Fightserver(in);
        } else {
            server.update(in);
        }
    }

    private static void removeStopped() {
        Instant timeout = Instant.now().minus(5, ChronoUnit.SECONDS);

        Iterator<Map.Entry<String, Fightserver>> it = servers.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Fightserver> server = it.next();
            if (timeout.isAfter(server.getValue().lastUpdate)) {
                server.getValue().remove();
                it.remove();
            }
        }
    }

    private final List<FightserverPortal> portals = new ArrayList<>();

    private FightInfoPacket fightInfo;
    private Instant lastUpdate;

    private Fightserver(FightInfoPacket fightInfo) {
        this.fightInfo = fightInfo;

        update(fightInfo);

        setupPortal(getGameMode().toLowerCase());
        setupPortal("all");

        servers.put(getServerName(), this);
    }

    private void setupPortal(String gameMode) {
        FightserverPortal portal = FightserverPortal.findFree(gameMode);
        if (portal == null) return;

        portals.add(portal);
        portal.setServer(this);
    }

    public String getGameMode() {
        return fightInfo.getGameMode();
    }

    public String getServerName() {
        return fightInfo.getServerName();
    }

    public FightInfoPacket current() {
        return fightInfo;
    }

    private void update(FightInfoPacket fightInfo) {
        FightInfoPacket old = this.fightInfo;
        this.fightInfo = fightInfo;
        lastUpdate = Instant.now();

        update(old.getBluePlayers(), fightInfo.getBluePlayers(), FightserverPortal::updateBluePlayers);
        update(old.getRedPlayers(), fightInfo.getRedPlayers(), FightserverPortal::updateRedPlayers);
        update(old.getCountdown(), fightInfo.getCountdown(), FightserverPortal::updateText);
        update(old.getFightState(), fightInfo.getFightState(), FightserverPortal::updateText);
    }

    private <T> void update(T old, T current, Consumer<FightserverPortal> observer) {
        if (!old.equals(current)) portals.forEach(observer);
    }

    private void remove() {
        portals.forEach(portal -> portal.setServer(null));
        portals.clear();
    }
}
