/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2023  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.script;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.script.lua.SteamWarPlatform;
import de.steamwar.bausystem.utils.ItemUtils;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.Script;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.luaj.vm2.Globals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

@Linked
public class ScriptGUI implements Listener {
    public static void open(Player player) {
        open(player, null);
    }

    private static void open(Player player, ItemStack setCursor) {
        SteamwarUser user = SteamwarUser.get(player.getUniqueId());
        List<SWListInv.SWListEntry<Script>> entries = new ArrayList<>();
        List<String> lore = new ArrayList<>();
        Globals globals = SteamWarPlatform.createGlobalParser(
                (eventType, luaFunction) -> lore.add(BauSystem.MESSAGE.parse("SCRIPT_EVENT_ITEM_NAME", player, eventType.name())),
                (s, luaFunction) -> lore.add(BauSystem.MESSAGE.parse("SCRIPT_HOTKEY_ITEM_NAME", player, s)),
                commandRegister -> lore.add(BauSystem.MESSAGE.parse("SCRIPT_COMMAND_ITEM_NAME", player, commandRegister.getName()))
        );

        Script.list(user).forEach(script -> {
            try {
                globals.load(script.getCode()).call();
            } catch (Exception e) {
                String[] sp = e.getMessage().split(":");
                lore.add(BauSystem.MESSAGE.parse("SCRIPT_ERROR_GUI", player, String.join(":", Arrays.copyOfRange(sp, 1, sp.length))));
            }

            if(!lore.isEmpty()) {
                lore.add("");
            }
            lore.add(BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_LORE_1", player));
            lore.add(BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_LORE_2", player));
            lore.add(BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_LORE_3", player));
            lore.add(BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_LORE_4", player));

            entries.add(new SWListInv.SWListEntry<>(new SWItem(Material.ENCHANTED_BOOK, script.getName(), new ArrayList<>(lore), false, clickType -> {}), script));
            lore.clear();
        });

        SWListInv<Script> inv = new SWListInv<>(player, BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_NAME", player), false, entries, (clickType, script) -> {
            ItemStack itemStack = ScriptHelper.getScriptItem(script, clickType.isRightClick());

            if(clickType == ClickType.MIDDLE) {
                player.openBook(itemStack);
            } else if(!clickType.isShiftClick()) {
                script.delete();
                ScriptRunner.updateGlobalScript(player);
                open(player, itemStack);
            } else {
                player.getOpenInventory().setCursor(itemStack);
            }
        });
        inv.setItem(49, Material.HOPPER, BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_ADD_NAME", player), Collections.singletonList(BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ITEM_ADD_LORE", player)), false, click -> {
            if(player.getOpenInventory().getCursor() != null) {
                ItemStack cursor = player.getOpenInventory().getCursor();
                if(!(cursor.getItemMeta() instanceof BookMeta)) {
                    return;
                }

                BookMeta meta = (BookMeta) cursor.getItemMeta();
                if(meta == null) {
                    return;
                }

                saveWithName(player, meta, meta.getTitle());
            }
        });
        inv.open();
        if(setCursor != null) {
            player.getOpenInventory().setCursor(setCursor);
        }
    }

    private static void saveWithName(Player player, BookMeta meta, String name) {
        SteamwarUser user = SteamwarUser.get(player.getUniqueId());
        if(name != null && Script.list(user).stream().noneMatch(script -> script.getName().equalsIgnoreCase(name))) {
            Script.create(user, name, ScriptHelper.getScriptString(meta.getPages()));
            player.getOpenInventory().setCursor(null);
            ScriptRunner.updateGlobalScript(player);
            open(player);
        } else {
            SWAnvilInv inv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("SCRIPT_MENU_GUI_ENTER_NAME", player), name == null ? "" : name);
            AtomicBoolean saved = new AtomicBoolean(false);
            ItemStack itemStack = player.getOpenInventory().getCursor();
            inv.setCallback(s -> {
                saveWithName(player, meta, s);
                saved.set(true);
            });
            inv.addCloseCallback(() -> {
                Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
                    if (saved.get()) return;
                    SWUtils.giveItemToPlayer(player, itemStack);
                }, 1);
            });
            inv.open();
        }
    }
}
