package io.github.aquerr.eaglefactions.entities;

import io.github.aquerr.eaglefactions.EagleFactionsPlugin;
import io.github.aquerr.eaglefactions.api.entities.Faction;
import io.github.aquerr.eaglefactions.api.entities.FactionChest;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.spongepowered.api.item.inventory.ContainerTypes;
import org.spongepowered.api.item.inventory.Inventory;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.item.inventory.Slot;
import org.spongepowered.api.item.inventory.menu.InventoryMenu;
import org.spongepowered.api.item.inventory.type.ViewableInventory;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;

public class FactionChestImpl implements FactionChest
{
    private String factionName; //Reference to faction holding this chest
    private Supplier<Inventory> inventory;
    private Inventory rawInventory;

    public FactionChestImpl(final String factionName)
    {
        this.factionName = factionName;
    }

    public FactionChestImpl(final String factionName, final List<SlotItem> items)
    {
        this.factionName = factionName;
        this.inventory = () -> {
            if (this.rawInventory != null)
                return this.rawInventory;
            return buildInventory(items);
        };
    }

    public FactionChestImpl(final String factionName, final Inventory inventory)
    {
        this.factionName = factionName;
        this.inventory = () -> {
            if (this.rawInventory != null)
                return this.rawInventory;
            return buildInventory(toSlotItems(inventory));
        };
    }

    @Override
    public String getFactionName()
    {
        return this.factionName;
    }

    @Override
    public List<SlotItem> getItems()
    {
        if(this.inventory == null)
            return new ArrayList<>();
        return toSlotItems(this.inventory.get());
    }

    @Override
    public Inventory getInventory()
    {
        if(this.inventory.get() == null)
            this.rawInventory = buildInventory(new ArrayList<>());
        return this.rawInventory;
    }

    private Inventory buildInventory(final List<SlotItem> slotItems)
    {
        FactionChest factionChest = this;

        //Create inventory
        InventoryMenu inventoryMenu = InventoryMenu.of(ViewableInventory.builder().type(ContainerTypes.GENERIC_9X3)
                .completeStructure()
                .identity(UUID.randomUUID())
                .plugin(EagleFactionsPlugin.getPlugin().getPluginContainer())
                .build());
        inventoryMenu.setTitle(Component.text("Faction's chest", NamedTextColor.BLUE));
        inventoryMenu.registerClose((cause, container) ->
        {
            final Faction faction = EagleFactionsPlugin.getPlugin().getFactionLogic().getFactionByName(factionName);
            if(faction != null)
            {
                EagleFactionsPlugin.getPlugin().getFactionLogic().setChest(faction, factionChest);
            }
        });

        //Fill it with items
        int column = 1;
        int row = 1;

        for(final Inventory slot : inventory.get().slots())
        {
            ItemStack itemStack = getAtPosition(slotItems, row, column);
            if(itemStack != null)
                slot.offer(itemStack);

            column++;
            if(column > 9)
            {
                column = 1;
                row++;
            }
        }

        return inventoryMenu.inventory();
    }

    private List<SlotItem> toSlotItems(final Inventory inventory)
    {
        final List<FactionChest.SlotItem> slotItemList = new ArrayList<>();
        final List<Slot> slots = inventory.slots();
        int column = 1;
        int row = 1;
        for(Inventory slot : slots)
        {
            ItemStack itemStack = slot.peek();
            if(itemStack != ItemStack.empty())
            {
                slotItemList.add(new FactionChestImpl.SlotItemImpl(column, row, itemStack));
            }

            column++;
            if(column > 9)
            {
                row++;
                column = 1;
            }

            if(row > 3)
                break;
        }
        return slotItemList;
    }

    private ItemStack getAtPosition(final List<SlotItem> items, int row, int column)
    {
        ItemStack itemStack = null;
        for(SlotItem slotItem : items)
        {
            if(slotItem.getRow() == row && slotItem.getColumn() == column)
                itemStack = slotItem.getItem().copy();
        }

        return itemStack;
    }

    public static final class SlotItemImpl implements FactionChest.SlotItem
    {
        private int column;
        private int row;
        private ItemStack item;

        public SlotItemImpl()
        {

        }

        public SlotItemImpl(int column, int row, ItemStack item)
        {
            this.column = column;
            this.row = row;
            this.item = item;
        }

        public int getColumn()
        {
            return this.column;
        }

        public int getRow()
        {
            return this.row;
        }

        public ItemStack getItem()
        {
            return this.item;
        }
    }
}

@@ -956,24 +956,32 @@
 y%3E inventory
+Supplier
 ;%0A    privat
@@ -1256,32 +1256,40 @@
   this.inventory
+Supplier
  = () -%3E %7B%0A     
@@ -1372,38 +1372,51 @@
 ry;%0A            
-return
+this.rawInventory =
  buildInventory(
@@ -1423,16 +1423,54 @@
 items);%0A
+            return this.rawInventory;%0A
         
@@ -1550,32 +1550,40 @@
 entory inventory
+Supplier
 )%0A    %7B%0A        
@@ -1636,16 +1636,24 @@
 nventory
+Supplier
  = () -%3E
@@ -1752,22 +1752,35 @@
         
-return
+this.rawInventory =
  buildIn
@@ -1808,18 +1808,64 @@
 nventory
-))
+Supplier));%0A            return this.rawInventory
 ;%0A      
@@ -2053,16 +2053,24 @@
 nventory
+Supplier
  == null
@@ -2146,24 +2146,32 @@
 is.inventory
+Supplier
 .get());%0A   
@@ -2242,70 +2242,29 @@
     
-if(this.inventory.get() == null)%0A           
+return
  this.
-rawI
+i
 nventory
  = b
@@ -2263,78 +2263,22 @@
 tory
- = buildInventory(new ArrayList%3C%3E());%0A        return this.rawInventory
+Supplier.get()
 ;%0A  
@@ -3294,20 +3294,30 @@
 nventory
-.get
+Menu.inventory
 ().slots

Fix building chests