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

import de.steamwar.core.Core;
import de.steamwar.data.CMDs;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SchematicType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;

import java.util.*;
import java.util.stream.Collectors;

public class SWListInv<T> extends SWInventory {

    private final List<SWListEntry<T>> elements;

    private final Map<Integer, SWItem> customItems = new HashMap<>();
    private final boolean dynamicSize;
    private ListCallback<T> callback;
    private int page;
    private boolean opened = false;

    public SWListInv(Player p, String t, List<SWListEntry<T>> l, ListCallback<T> c) {
        this(p, t, true, l, c);
    }

    public SWListInv(Player p, String t, boolean dynamicSize, List<SWListEntry<T>> l, ListCallback<T> c) {
        super(p, dynamicSize ? dynamicSize(l.size()) : 54, t);
        callback = c;
        elements = l;
        page = 0;
        this.dynamicSize = dynamicSize;
    }

    @Override
    public void open() {
        opened = true;
        inventory.clear();
        callbacks.keySet().stream().filter(i -> i >= 0).collect(Collectors.toList()).forEach(callbacks::remove);
        if (!callbacks.containsKey(-999)) {
            setCallback(-999, (ClickType click) -> player.closeInventory());
        }

        if (sizeBiggerMax()) {
            if (page != 0) {
                setItem(45, new SWItem(Material.LIME_DYE, (byte) 10, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_ACTIVE", player), (ClickType click) -> {
                    page--;
                    open();
                }).setCustomModelData(CMDs.PREVIOUS_PAGE));
            } else {
                setItem(45, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
                }).setCustomModelData(CMDs.PREVIOUS_PAGE));
            }
            if (page < elements.size() / 45 - (elements.size() % 45 == 0 ? 1 : 0)) {
                setItem(53, new SWItem(Material.LIME_DYE, (byte) 10, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_ACTIVE", player), (ClickType click) -> {
                    page++;
                    open();
                }).setCustomModelData(CMDs.NEXT_PAGE));
            } else {
                setItem(53, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
                }).setCustomModelData(CMDs.NEXT_PAGE));
            }
        } else if (!dynamicSize) {
            setItem(45, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> {
            }).setCustomModelData(CMDs.PREVIOUS_PAGE));
            setItem(53, new SWItem(Material.GRAY_DYE, (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> {
            }).setCustomModelData(CMDs.NEXT_PAGE));
        }

        int ipageLimit = elements.size() - page * 45;
        if (ipageLimit > 45 && sizeBiggerMax()) {
            ipageLimit = 45;
        }
        int i = page * 45;
        for (int ipage = 0; ipage < ipageLimit; ipage++) {
            SWItem e = elements.get(i).getItem();

            final int pos = i;
            setItem(ipage, e);
            setCallback(ipage, (ClickType click) -> callback.clicked(click, elements.get(pos).getObject()));
            i++;
        }

        for (Map.Entry<Integer, SWItem> customItem : customItems.entrySet()) {
            setItem(customItem.getKey(), customItem.getValue());
        }
        super.open();
    }

    @Override
    public void setItem(int pos, SWItem item) {
        super.setItem(pos, item);
        if (!opened) customItems.put(pos, item);
    }

    public void setCallback(ListCallback<T> c) {
        callback = c;
    }

    public static List<SWListEntry<UUID>> createPlayerList(UUID without) {
        List<SWListEntry<UUID>> onlinePlayers = new ArrayList<>();
        for (Player player : Bukkit.getOnlinePlayers()) {
            if (without != null && player.getUniqueId().equals(without)) continue;

            onlinePlayers.add(new SWListEntry<>(SWItem.getPlayerSkull(player), player.getUniqueId()));
        }
        return onlinePlayers;
    }

    public static List<SWListEntry<SchematicNode>> getSchemnodeList(SchematicType type, int steamwarUserId) {
        List<SWListEntry<SchematicNode>> schemList = new ArrayList<>();

        List<SchematicNode> schems;
        if (type == null) {
            schems = SchematicNode.getAllSchematicsAccessibleByUser(steamwarUserId);
        } else {
            schems = SchematicNode.getAllAccessibleSchematicsOfType(steamwarUserId, type.toDB());
        }

        for (SchematicNode s : schems) {
            Material m;
            if (s.getItem().isEmpty()) {
                m = Material.CAULDRON;
            } else {
                m = SWItem.getMaterial(s.getItem());
            }
            SWItem item = new SWItem(m, "§e" + s.getName());
            item.setEnchanted(s.isDir());
            schemList.add(new SWListEntry<>(item, s));
        }
        return schemList;
    }

    private boolean sizeBiggerMax() {
        return dynamicSize ? elements.size() > 54 : elements.size() > 45;
    }

    private static int dynamicSize(int size) {
        return (size > 45) ? 54 : (size + 9 - size % 9);
    }

    public interface ListCallback<T> {
        void clicked(ClickType click, T element);
    }

    public static class SWListEntry<T> {
        final SWItem item;
        final T object;

        public SWListEntry(SWItem item, T object) {
            this.item = item;
            this.object = object;
        }

        public SWItem getItem() {
            return item;
        }

        public T getObject() {
            return object;
        }
    }
}
