/*
 *   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 de.steamwar.data.GameModeConfigUtils;
import de.steamwar.fightsystem.utils.Region;
import de.steamwar.fightsystem.winconditions.Winconditions;
import de.steamwar.sql.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;

import java.io.File;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;

public class Config {

    private Config() {
    }

    public static final World world = Bukkit.getWorlds().get(0);

    public static final GameModeConfig<Material, Winconditions> GameModeConfig;

    //arena parameter
    public static final Region BluePasteRegion;
    public static final Region RedPasteRegion;
    public static final Region BlueExtendRegion;
    public static final Region RedExtendRegion;
    public static final Region ArenaRegion;
    public static final Region PlayerRegion;
    public static final Region BlueInsetRegion;

    public static final Location TeamBlueSpawn;
    public static final Location TeamRedSpawn;
    public static final Location SpecSpawn;

    public static final int BlueToRedX;
    private static final int BlueToRedY;
    public static final int BlueToRedZ;

    //schematic parameter
    public static final boolean OnlyPublicSchematics;

    public static final boolean RedRotate;
    public static final boolean BlueRotate;

    //team parameter
    public static final String TeamRedName;
    public static final String TeamBlueName;
    public static final String TeamRedColor;
    public static final String TeamBlueColor;
    public static final UUID BlueLeader;
    public static final UUID RedLeader;

    //event parameter
    public static final EventFight EventKampf;
    private static final Set<Integer> Referees;
    public static final int EventTeamBlueID;
    public static final int EventTeamRedID;
    public static final boolean BothTeamsPublic;
    public static final int MaximumTeamMembers;
    public static final boolean LiveReplay;

    //check parameter
    public static final int CheckSchemID;
    public static final int PrepareSchemID;

    public static final ArenaMode mode;

    //replay system parameter
    public static final String spectateIP = "127.0.0.1";
    public static final int SpectatePort;
    public static final int ReplayID;

    static {
        CheckSchemID = Integer.parseInt(System.getProperty("checkSchemID", "0"));
        PrepareSchemID = Integer.parseInt(System.getProperty("prepareSchemID", "0"));
        ReplayID = Integer.parseInt(System.getProperty("replay", "0"));

        String configFile = System.getProperty("config", "config.yml");
        if (!new File(FightSystem.getPlugin().getDataFolder(), configFile).exists()) {
            FightSystem.getPlugin().saveDefaultConfig();
            Bukkit.getLogger().log(Level.SEVERE, "Arenaconfig fehlt!");
            Bukkit.shutdown();
        }
        GameModeConfig = new GameModeConfig<>(new File(FightSystem.getPlugin().getDataFolder(), configFile), GameModeConfigUtils.ToMaterial, Winconditions::valueOf, de.steamwar.sql.GameModeConfig.ToStaticWarGear, false);

        File worldConfigFile = new File(world.getWorldFolder(), "config.yml");
        if (!worldConfigFile.exists()) {
            Bukkit.getLogger().log(Level.SEVERE, "Weltconfig fehlt!");
            Bukkit.shutdown();
        }
        FileConfiguration worldconfig = YamlConfiguration.loadConfiguration(worldConfigFile);

        int blueCornerX = worldconfig.getInt("BlueCorner.x");
        int blueCornerY = worldconfig.getInt("BlueCorner.y");
        int blueCornerZ = worldconfig.getInt("BlueCorner.z");
        int underBorder = worldconfig.getInt("UnderBorder", blueCornerY);

        BlueToRedX = worldconfig.getInt("BlueToRed.x", 0);
        BlueToRedY = worldconfig.getInt("BlueToRed.y", 0);
        BlueToRedZ = worldconfig.getInt("BlueToRed.z", GameModeConfig.Schematic.Size.z + 50);

        int teamRedCornerX = BlueToRedX + blueCornerX;
        int teamRedCornerY = BlueToRedY + blueCornerY;
        int teamRedCornerZ = BlueToRedZ + blueCornerZ;

        int teamBluePasteX = blueCornerX + GameModeConfig.Schematic.Size.x / 2;
        int teamBluePasteZ = blueCornerZ + GameModeConfig.Schematic.Size.z / 2;
        int teamRedPasteX = teamBluePasteX + BlueToRedX;
        int teamRedPasteZ = teamBluePasteZ + BlueToRedZ;

        TeamBlueSpawn = new Location(world,
                teamBluePasteX + 0.5 + GameModeConfig.Arena.SpawnOffset.x,
                blueCornerY + 0.5 + GameModeConfig.Arena.SpawnOffset.y,
                teamBluePasteZ + 0.5 + GameModeConfig.Arena.SpawnOffset.z);

        TeamRedSpawn = new Location(world,
                teamRedPasteX + 0.5 - GameModeConfig.Arena.SpawnOffset.x,
                teamRedCornerY + 0.5 + GameModeConfig.Arena.SpawnOffset.y,
                teamRedPasteZ + 0.5 - GameModeConfig.Arena.SpawnOffset.z);

        SpecSpawn = new Location(world,
                teamBluePasteX + BlueToRedX / 2.0,
                blueCornerY + BlueToRedY / 2.0 + GameModeConfig.Schematic.Size.y / 2.0,
                teamBluePasteZ + BlueToRedZ / 2.0);

        Vector v1 = TeamBlueSpawn.toVector().subtract(TeamRedSpawn.toVector());
        double pitch = Math.toDegrees(v1.angle(v1.clone().setY(0)));
        double yaw = Math.toDegrees(v1.clone().setY(0).angle(new Vector(0, 0, 1)));

        TeamBlueSpawn.setYaw((float) yaw + 180);
        TeamBlueSpawn.setPitch((float) pitch);

        TeamRedSpawn.setYaw((float) yaw);
        TeamRedSpawn.setPitch((float) pitch * -1);


        boolean teamRedRotate;
        boolean teamBlueRotate;
        int arenaMinX;
        int arenaMaxX;
        int arenaMinZ;
        int arenaMaxZ;
        if (BlueToRedX > 0) {
            arenaMinX = blueCornerX - GameModeConfig.Arena.Schem2Border.x;
            arenaMaxX = teamRedCornerX + GameModeConfig.Schematic.Size.x + GameModeConfig.Arena.Schem2Border.x;
            teamRedRotate = true;
            teamBlueRotate = false;
        } else {
            arenaMinX = teamRedCornerX - GameModeConfig.Arena.Schem2Border.x;
            arenaMaxX = blueCornerX + GameModeConfig.Schematic.Size.x + GameModeConfig.Arena.Schem2Border.x;
            teamRedRotate = false;
            teamBlueRotate = true;
        }
        if (BlueToRedZ > 0) {
            arenaMinZ = blueCornerZ - GameModeConfig.Arena.Schem2Border.z;
            arenaMaxZ = teamRedCornerZ + GameModeConfig.Schematic.Size.z + GameModeConfig.Arena.Schem2Border.z;
            teamRedRotate = true;
            teamBlueRotate = false;
        } else {
            arenaMinZ = teamRedCornerZ - GameModeConfig.Arena.Schem2Border.z;
            arenaMaxZ = blueCornerZ + GameModeConfig.Schematic.Size.z + GameModeConfig.Arena.Schem2Border.z;
            if (BlueToRedZ != 0) {
                teamRedRotate = false;
                teamBlueRotate = true;
            }
        }
        if (!GameModeConfig.Schematic.Rotate) {
            teamRedRotate = false;
            teamBlueRotate = false;
        }
        RedRotate = teamRedRotate;
        BlueRotate = teamBlueRotate;

        RedPasteRegion = Region.fromSize(teamRedCornerX, teamRedCornerY, teamRedCornerZ, GameModeConfig.Schematic.Size.x, GameModeConfig.Schematic.Size.y, GameModeConfig.Schematic.Size.z);
        BluePasteRegion = Region.fromSize(blueCornerX, blueCornerY, blueCornerZ, GameModeConfig.Schematic.Size.x, GameModeConfig.Schematic.Size.y, GameModeConfig.Schematic.Size.z);

        RedExtendRegion = Region.withExtension(teamRedCornerX, teamRedCornerY, teamRedCornerZ, GameModeConfig.Schematic.Size.x, GameModeConfig.Schematic.Size.y, GameModeConfig.Schematic.Size.z, GameModeConfig.Arena.BorderFromSchematic, GameModeConfig.Arena.BorderFromSchematic, GameModeConfig.Arena.BorderFromSchematic);
        BlueExtendRegion = Region.withExtension(blueCornerX, blueCornerY, blueCornerZ, GameModeConfig.Schematic.Size.x, GameModeConfig.Schematic.Size.y, GameModeConfig.Schematic.Size.z, GameModeConfig.Arena.BorderFromSchematic, GameModeConfig.Arena.BorderFromSchematic, GameModeConfig.Arena.BorderFromSchematic);
        ArenaRegion = Region.withExtension(arenaMinX, blueCornerY, arenaMinZ, arenaMaxX - arenaMinX, GameModeConfig.Schematic.Size.y, arenaMaxZ - arenaMinZ, 0, GameModeConfig.Arena.BorderFromSchematic, 0);
        PlayerRegion = new Region(arenaMinX, underBorder, arenaMinZ, arenaMaxX, world.getMaxHeight(), arenaMaxZ);

        BlueInsetRegion = new Region(BluePasteRegion.getMinX() + GameModeConfig.Schematic.Inset.x, BluePasteRegion.getMinY() + GameModeConfig.Schematic.Inset.bottom, BluePasteRegion.getMinZ() + GameModeConfig.Schematic.Inset.z, BluePasteRegion.getMaxX() - GameModeConfig.Schematic.Inset.x, BluePasteRegion.getMaxY() - GameModeConfig.Schematic.Inset.top, BluePasteRegion.getMaxZ() - GameModeConfig.Schematic.Inset.z);

        int eventKampfID = Integer.parseInt(System.getProperty("fightID", "0"));
        if (eventKampfID >= 1) {
            EventKampf = EventFight.byId(eventKampfID);
            if (EventKampf == null) {
                Bukkit.getLogger().log(Level.SEVERE, "Failed to load EventFight");
                Bukkit.shutdown();
            }

            assert EventKampf != null;
            Team team1 = Team.byId(EventKampf.getTeamBlue());
            Team team2 = Team.byId(EventKampf.getTeamRed());

            if (team1 == null || team2 == null) {
                Bukkit.getLogger().log(Level.SEVERE, "Failed to load Team");
                Bukkit.shutdown();
            }

            assert team1 != null;
            assert team2 != null;
            TeamBlueName = team1.getTeamKuerzel();
            TeamRedName = team2.getTeamKuerzel();
            TeamBlueColor = "§" + team1.getTeamColor();
            TeamRedColor = "§" + team2.getTeamColor();
            EventTeamBlueID = team1.getTeamId();
            EventTeamRedID = team2.getTeamId();
            BothTeamsPublic = EventTeamRedID == 0 && EventTeamBlueID == 0;
            SpectatePort = EventKampf.getSpectatePort() == null ? 0 : EventKampf.getSpectatePort();
            LiveReplay = SpectatePort != 0;
            Referees = Referee.get(Config.EventKampf.getEventID());

            Event event = Event.byId(EventKampf.getEventID());
            if (BothTeamsPublic) {
                OnlyPublicSchematics = true;
                MaximumTeamMembers = Integer.MAX_VALUE;
            } else {
                OnlyPublicSchematics = event.publicSchemsOnly();
                MaximumTeamMembers = event.getMaximumTeamMembers();
            }
        } else {
            //No event
            TeamRedColor = GameModeConfig.Red.Prefix;
            TeamBlueColor = GameModeConfig.Blue.Prefix;
            TeamRedName = GameModeConfig.Red.Name;
            TeamBlueName = GameModeConfig.Blue.Name;
            OnlyPublicSchematics = GameModeConfig.Schematic.OnlyPublicSchematics;
            EventTeamBlueID = 0;
            EventTeamRedID = 0;
            EventKampf = null;
            BothTeamsPublic = true;
            Referees = Collections.emptySet();
            MaximumTeamMembers = Integer.MAX_VALUE;
            LiveReplay = false;
            SpectatePort = -ReplayID;
        }

        String blueLeader = System.getProperty("blueLeader", null);
        String redLeader = System.getProperty("redLeader", null);
        if (blueLeader != null) {
            BlueLeader = UUID.fromString(blueLeader);
        } else {
            BlueLeader = null;
        }
        if (redLeader != null) {
            RedLeader = UUID.fromString(redLeader);
        } else {
            RedLeader = null;
        }

        if (CheckSchemID != 0) {
            mode = ArenaMode.CHECK;
        } else if (PrepareSchemID != 0) {
            mode = ArenaMode.PREPARE;
        } else if (eventKampfID >= 1) {
            mode = ArenaMode.EVENT;
        } else if (eventKampfID == -1) {
            mode = ArenaMode.TEST;
        } else if (ReplayID != 0) {
            mode = ArenaMode.REPLAY;
        } else {
            mode = ArenaMode.NORMAL;
        }
    }

    public static boolean test() {
        return ArenaMode.Test.contains(mode);
    }

    public static boolean replayserver() {
        return ReplayID < 0;
    }

    public static boolean blueNegZ() {
        return BlueToRedZ > 0;
    }

    public static boolean isReferee(Player player) {
        return Referees.contains(SteamwarUser.get(player.getUniqueId()).getId());
    }
}
