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

import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.fightsystem.utils.Message;
import org.bukkit.Material;
import org.bukkit.block.Block;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

public abstract class WinconditionBlocks extends Wincondition implements PrintableWincondition {

    public static final Material PUMPKIN_LANTERN = Material.JACK_O_LANTERN;

    private final Map<FightTeam, TeamBlocks> teamMap = new HashMap<>();
    private final String barMessage;
    private final Predicate<Block> isOfType;

    public WinconditionBlocks(Winconditions wincondition, String windescription, String barMessage, Predicate<Block> isOfType) {
        super(windescription);
        this.barMessage = barMessage;
        this.isOfType = isOfType;
        Fight.teams().forEach(team -> teamMap.put(team, new TeamBlocks(team)));

        new StateDependentTask(wincondition, FightState.Ingame, () -> teamMap.values().forEach(TeamBlocks::check), 200, 200) {
            @Override
            public void enable() {
                teamMap.values().forEach(TeamBlocks::find);
                super.enable();
            }
        };

        if (Config.GameModeConfig.WinConditions.contains(wincondition)) {
            printableWinconditions.add(this);
        }
    }

    @Override
    public Message getDisplay(FightTeam team) {
        return new Message(barMessage, team.getPrefix() + teamMap.get(team).blocks.size());
    }

    private class TeamBlocks {
        private final FightTeam team;
        private final List<Block> blocks = new ArrayList<>();

        private TeamBlocks(FightTeam team) {
            this.team = team;
        }

        private void find() {
            blocks.clear();
            team.getExtendRegion().forEach((x, y, z) -> {
                Block block = Config.world.getBlockAt(x, y, z);
                if (isOfType.test(block)) {
                    blocks.add(block);
                }
            });
        }

        private void check() {
            // Edge Case for DirtBlock
            if (blocks.isEmpty()) return;

            blocks.removeIf(block -> !isOfType.test(block));
            if (blocks.isEmpty()) {
                win(Fight.getOpposite(team), "WIN_TECHKO", team.getColoredName());
            }
        }
    }
}
