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

import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.fightsystem.commands.TechareaCommand;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.listener.ClickAnalyzer;
import de.steamwar.fightsystem.listener.PistonListener;
import de.steamwar.fightsystem.record.FileSource;
import de.steamwar.fightsystem.record.GlobalRecorder;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.FightUI;
import de.steamwar.fightsystem.utils.HullHider;
import de.steamwar.fightsystem.utils.SWSound;
import de.steamwar.fightsystem.utils.TechHiderWrapper;
import de.steamwar.linkage.AbstractLinker;
import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerPickupArrowEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class FightSystem extends JavaPlugin {

    @Getter
    private static FightSystem plugin;

    private Message message;
    private FightTeam lastWinner;
    private String lastWinreason;
    private TechHiderWrapper techHider;
    private HullHider hullHider;

    private SpigotLinker spigotLinker;

    @Override
    public void onLoad() {
        plugin = this;
    }

    @Override
    public void onEnable() {
        if (Core.getInstance() == null) {
            Core.setInstance(this);
            TinyProtocol.init();
        }
        if (Config.SpectatePort != 0) {
            Core.setServerName("Spectate");
        } else if (Config.ReplayID != 0) {
            Core.setServerName("Replay");
        }

        message = new Message("de.steamwar.fightsystem.FightSystem", FightSystem.class.getClassLoader());

        spigotLinker = new SpigotLinker(this, message) {
            @Override
            protected void linkObject(Object any) {
                // No Init needed for FightSystem!
            }
        };
        try {
            spigotLinker.link();
        } catch (AbstractLinker.LinkException e) {
            e.printStackTrace();
            Bukkit.shutdown();
            return;
        }

        new PistonListener(ArenaMode.AntiTestCheckPrepare, e -> e.setCancelled(true));
        new PistonListener(ArenaMode.Test, e -> getMessage().broadcastActionbar("PISTON_PUSHED_OUTSIDE"));
        new PistonListener(ArenaMode.Prepare, e -> {
            getMessage().broadcast("PISTON_PUSHED_OUTSIDE");
            shutdown();
        });
        new StateDependentListener(ArenaMode.All, FightState.All, new Listener() {
            @EventHandler
            public void onArrowPickup(PlayerPickupArrowEvent e) {
                if (Fight.fighting(e.getPlayer())) e.setCancelled(true);
            }
        });
        new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
        new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
        Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode));

        hullHider = new HullHider();
        techHider = new TechHiderWrapper(hullHider);
        FightSystem.getHullHider().getHullMap().values().forEach(hull -> hull.fill(true));


        FileSource.startReplay();

        if (Config.mode == ArenaMode.EVENT) {
            FightState.setFightState(FightState.PRE_SCHEM_SETUP);
        } else if (Config.mode == ArenaMode.CHECK) {
            SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(Config.CheckSchemID);
            Fight.getBlueTeam().setSchem(checkSchematicNode);

            if (checkSchematicNode.isPrepared()) {
                Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1);
            }

            new TechareaCommand();
        } else if (Config.mode == ArenaMode.PREPARE) {
            Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID));
        }

        Config.world.setGameRule(GameRule.LOCATOR_BAR, false);
    }

    @Override
    public void onDisable() {
        GlobalRecorder.getInstance().close();
        ClickAnalyzer.close();
        spigotLinker.unlink();
    }

    public static void setSpectateState(FightTeam winFightTeam, String winreason, String subtitle, Object... params) {
        plugin.lastWinner = winFightTeam;
        plugin.lastWinreason = winreason;
        FightUI.printWin(winFightTeam, subtitle, params);

        FightState.setFightState(FightState.SPECTATE);
    }

    public static Message getMessage() {
        return plugin.message;
    }

    public static FightTeam getLastWinner() {
        return plugin.lastWinner;
    }

    public static String getLastWinreason() {
        return plugin.lastWinreason;
    }

    public static TechHiderWrapper getTechHider() {
        return plugin.techHider;
    }

    public static HullHider getHullHider() {
        return plugin.hullHider;
    }

    public static void shutdown() {
        //Staggered kick to prevent lobby overloading
        if (Bukkit.getOnlinePlayers().isEmpty()) {
            Bukkit.shutdown();
            return;
        }

        Bukkit.getOnlinePlayers().iterator().next().kickPlayer(null);
        Bukkit.getScheduler().runTaskLater(plugin, FightSystem::shutdown, 10);
    }
}
