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

import com.google.common.io.Files;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui;
import de.steamwar.bausystem.features.simulator.storage.SimFormatSimulatorLoader;
import de.steamwar.bausystem.features.simulator.storage.SimulatorFormatSimulatorLoader;
import de.steamwar.bausystem.features.simulator.storage.SimulatorSaver;
import de.steamwar.bausystem.features.simulator.storage.YAPIONFormatSimulatorLoader;
import de.steamwar.bausystem.utils.ItemUtils;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.inventory.SWItem;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import de.steamwar.linkage.api.Enable;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Linked
@MinVersion(19)
public class SimulatorStorage implements Enable {

    public static final File simulatorsDir = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "simulators");
    private static Map<String, Simulator> simulatorMap = new HashMap<>();
    private static NamespacedKey simulatorSelection = SWUtils.getNamespaceKey("simulator_selection");

    public static Simulator getSimulator(Player player) {
        Simulator simulator = getSimulator(player.getInventory().getItemInMainHand());
        if (simulator != null) return simulator;
        return getSimulator(player.getInventory().getItemInOffHand());
    }

    public static Simulator getSimulator(ItemStack itemStack) {
        if (!SimulatorCursor.isSimulatorItem(itemStack)) {
            return null;
        }
        String selection = ItemUtils.getTag(itemStack, simulatorSelection);
        if (selection == null) {
            return null;
        }
        return simulatorMap.get(selection);
    }

    public static Simulator getSimulator(String name) {
        return simulatorMap.get(name);
    }

    public static void addSimulator(String name, Simulator simulator) {
        simulatorMap.putIfAbsent(name, simulator);
    }

    @Override
    public void enable() {
        SimFormatSimulatorLoader simFormatSimulatorLoader = new SimFormatSimulatorLoader();
        SimulatorFormatSimulatorLoader simulatorFormatSimulatorLoader = new SimulatorFormatSimulatorLoader();
        YAPIONFormatSimulatorLoader yapionFormatSimulatorLoader = new YAPIONFormatSimulatorLoader();

        File[] files = simulatorsDir.listFiles();
        if (files == null) return;
        for (File file : files) {
            try {
                List<Simulator> simulators = simFormatSimulatorLoader.load(file)
                        .orElse(null);
                if (simulators != null) {
                    simulators.forEach(simulator -> {
                        simulatorMap.put(simulator.getName(), simulator);
                    });
                    continue;
                }
            } catch (Exception e) {
                // Ignore
            }

            try {
                List<Simulator> simulators = simulatorFormatSimulatorLoader.load(file)
                        .orElse(null);
                if (simulators != null) {
                    simulators.forEach(simulator -> {
                        simulatorMap.put(simulator.getName(), simulator);
                        SimulatorSaver.saveSimulator(simulatorsDir, simulator);
                    });
                    continue;
                }
            } catch (Exception e) {
                // Ignore
            }

            try {
                List<Simulator> simulators = yapionFormatSimulatorLoader.load(file)
                        .orElse(null);
                if (simulators != null) {
                    simulators.forEach(simulator -> {
                        simulatorMap.put(simulator.getName(), simulator);
                        SimulatorSaver.saveSimulator(simulatorsDir, simulator);
                    });
                }
            } catch (Exception e) {
                // Ignore
            }
        }
    }

    public static void openSimulatorSelector(Player player) {
        SimulatorPageGui<Simulator> simulatorPageGui = new SimulatorPageGui<Simulator>(player, null, 6 * 9, simulatorMap.values().stream().sorted(Comparator.comparing(Simulator::getName)).collect(Collectors.toList())) {
            @Override
            public String baseTitle() {
                return "Simulators";
            }

            @Override
            public void headerAndFooter() {
                inventory.setItem(49, new SWItem(Material.NAME_TAG, "§eCreate", clickType -> {
                    SWAnvilInv anvilInv = new SWAnvilInv(player, "Name");
                    anvilInv.setCallback(s -> {
                        Simulator sim = SimulatorStorage.getSimulator(s);
                        if (sim != null) {
                            BauSystem.MESSAGE.send("SIMULATOR_NAME_ALREADY_EXISTS", player);
                            return;
                        }
                        if (!s.matches("[a-zA-Z_0-9-]+")) {
                            BauSystem.MESSAGE.send("SIMULATOR_NAME_INVALID", player);
                            return;
                        }
                        sim = new Simulator(s);
                        SimulatorStorage.addSimulator(s, sim);
                        SimulatorStorage.setSimulator(player, sim);
                    });
                    anvilInv.open();
                }));
            }

            @Override
            public SWItem convert(Simulator simulator) {
                return simulator.toItem(player, clickType -> {
                    setSimulator(player, simulator);
                    player.closeInventory();
                });
            }
        };
        simulatorPageGui.open();
    }

    public static ItemStack getWand(Player p) {
        ItemStack itemStack = new SWItem(Material.BLAZE_ROD, BauSystem.MESSAGE.parse("SIMULATOR_WAND_NAME", p), Arrays.asList(BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_1", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_2", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_3", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_4", p), BauSystem.MESSAGE.parse("SIMULATOR_WAND_LORE_5", p)), false, null).getItemStack();
        ItemMeta itemMeta = itemStack.getItemMeta();
        itemMeta.setCustomModelData(1);
        itemStack.setItemMeta(itemMeta);
        ItemUtils.setItem(itemStack, "simulator");
        return itemStack;
    }

    public static void setSimulator(Player player, Simulator simulator) {
        ItemStack mainHand = player.getInventory().getItemInMainHand();
        ItemStack offHand = player.getInventory().getItemInOffHand();
        ItemStack itemStack;
        if (SimulatorCursor.isSimulatorItem(mainHand)) {
            itemStack = mainHand;
        } else if (SimulatorCursor.isSimulatorItem(offHand)) {
            itemStack = offHand;
        } else {
            itemStack = null;
        }
        if (itemStack == null) {
            return;
        }

        ItemUtils.setTag(itemStack, simulatorSelection, simulator.getName());
        ItemMeta itemMeta = itemStack.getItemMeta();
        itemMeta.setDisplayName(BauSystem.MESSAGE.parse("SIMULATOR_WAND_NAME_SELECTED", player, simulator.getName()));
        itemStack.setItemMeta(itemMeta);
    }

    public static List<String> getSimulatorNames() {
        return new ArrayList<>(simulatorMap.keySet());
    }

    public static void delete(Simulator simulator) {
        simulatorMap.remove(simulator.getName());
        new File(simulatorsDir, simulator.getName() + ".sim").delete();
    }

    public static boolean copy(Simulator simulator, String name) {
        try {
            File file = new File(simulatorsDir, name + ".sim");
            Files.copy(new File(simulatorsDir, simulator.getName() + ".sim"), file);
            new SimFormatSimulatorLoader().load(file).ifPresent(simulators -> {
                simulators.forEach(sim -> {
                    simulatorMap.put(sim.getName(), sim);
                });
            });
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}
