package net.halbear.skyboxmod.rendering.screen;

import net.halbear.skyboxmod.Config;
import net.halbear.skyboxmod.SkyboxMod;
import net.halbear.skyboxmod.rendering.skybox.DistantSkyObject;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.components.toasts.SystemToast;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.packs.TransferableSelectionList;
import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import net.minecraft.util.Util;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.neoforged.fml.loading.FMLPaths;
import net.neoforged.neoforge.client.event.ContainerScreenEvent;
import net.neoforged.neoforge.client.event.ScreenEvent;
import net.neoforged.neoforge.common.NeoForge;
import org.jspecify.annotations.NonNull;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import static net.halbear.skyboxmod.Config.CloudsFolderName;
import static net.halbear.skyboxmod.Config.ResourceFolderName;

public class SelectionScreen extends Screen {

    private final Screen lastScreen;
    private final File targetDirectory;

    private final LinkedHashSet<Identifier> AllItemsLoaded = new LinkedHashSet<>();
    private final LinkedHashSet<Identifier> availableItems = new LinkedHashSet<>();
    private final LinkedHashSet<Identifier> selectedItems = new LinkedHashSet<>();

    private final ConcurrentLinkedQueue<Button> transferButtons = new ConcurrentLinkedQueue<Button>();

    private SelectionPanelList leftList;
    private SelectionPanelList rightList;


    public SelectionScreen(Screen lastScreen, File targetDirectory) {
        super(Component.literal("Cloud Asset Manager"));
        this.lastScreen = lastScreen;
        this.targetDirectory = targetDirectory;

    }

    @Override
    public void onFilesDrop(java.util.List<java.nio.file.Path> files) {
        for (java.nio.file.Path file : files) {
            try {
                java.nio.file.Files.copy(
                        file,
                        this.targetDirectory.toPath().resolve(file.getFileName().toString().toLowerCase().replace(' ','-')),
                        java.nio.file.StandardCopyOption.REPLACE_EXISTING
                );
            } catch (Exception e) {
                this.minecraft.getToastManager().addToast(SystemToast.multiline(
                        this.minecraft,
                        SystemToast.SystemToastId.PACK_COPY_FAILURE,
                        Component.literal("Error processing choice file"),
                        Component.literal(e.getMessage())
                ));
            }
        }
        this.refreshLoadedContent();
        this.refreshListData();
        this.rebuildWidgets();
    }

    @Override
    protected void init() {
        super.init();
        int listWidth = 170;
        int listHeight = this.height - 80;

        this.leftList = new SelectionPanelList(this.minecraft, listWidth, listHeight,48,64,this );
        this.leftList.setX(this.width / 2 - 180);


        this.rightList = new SelectionPanelList(this.minecraft, listWidth, listHeight,48,64,this);
        this.rightList.setX(this.width / 2 + 10);

        AllItemsLoaded.clear();
        selectedItems.clear();
        availableItems.clear();
        AllItemsLoaded.addAll(Config.Instance.GetAndLoadAllCloudFiles());
        selectedItems.addAll(Config.Instance.GetAllClouds());
        AllItemsLoaded.forEach(item->{
            SkyboxMod.LOGGER.debug(item.getPath());
            if(!selectedItems.contains(item)){
                availableItems.add(item);
            }
        });

        refreshListData();

        this.addRenderableWidget(this.leftList);
        this.addRenderableWidget(this.rightList);

        this.addRenderableWidget(Button.builder(
                Component.literal("Done"),
                button -> this.onClose()
        ).bounds(this.rightList.getX(), rightList.getY() + rightList.getHeight() + 4, this.rightList.getWidth(), 20 ).build());

        this.addRenderableWidget(Button.builder(Component.literal("Open Folder"),
                button -> {
                    Path ResourcesDir = FMLPaths.GAMEDIR.get().resolve(ResourceFolderName);
                    Path Clouds = ResourcesDir.resolve(CloudsFolderName);
                    if(!Files.isDirectory(Clouds)) {
                        try {
                            Files.createDirectories(Clouds);
                        } catch (Exception e) {
                            SkyboxMod.LOGGER.error("Failed to create Clouds directory", e);
                            return;
                        }
                    }
                    Util.getPlatform().openFile(Clouds.toFile());
                }).bounds(this.leftList.getX(), leftList.getY() + leftList.getHeight() + 4, this.leftList.getWidth(), 20 ).build());

    }

    private void refreshLoadedContent(){
        AllItemsLoaded.clear();
        selectedItems.clear();
        availableItems.clear();
        AllItemsLoaded.addAll(Config.Instance.GetAndLoadAllCloudFiles());
        selectedItems.addAll(Config.Instance.GetAllClouds());
        AllItemsLoaded.forEach(item->{
            SkyboxMod.LOGGER.debug(item.getPath());
            if(!selectedItems.contains(item)){
                availableItems.add(item);
            }
        });
    }

    private void refreshListData() {

        Button TransferBtn;
        while ((TransferBtn = transferButtons.poll()) != null) {
            renderables.remove(TransferBtn);
        }

        this.leftList.clearEntries();
        this.rightList.clearEntries();

        for (Identifier item : availableItems) {
            this.leftList.AddEntry(new TextRowEntry(item, true,this));
        }
        for (Identifier item : selectedItems) {
            this.rightList.AddEntry(new TextRowEntry(item, false,this));
        }
    }

    @Override
    public void extractBackground(GuiGraphicsExtractor guiGraphics, int mouseX, int mouseY, float partialTick) {
        super.extractBackground(guiGraphics, mouseX, mouseY, partialTick);
        guiGraphics.pose().pushMatrix();
        guiGraphics.text(this.font, this.title, this.width / 2 - this.font.width(this.title)/2, 8, 0xFFFFFFFF,true);
        guiGraphics.text(this.font, "Drag and drop sprites inside...", this.width / 2 - this.font.width("Drag and drop sprites inside...")/2, 20, 0xFFFFFFFF,true);
        guiGraphics.text(this.font, "All loaded clouds", leftList.getX(), 32, 0xFFFFFFFF,true);
        guiGraphics.text(this.font, "Selected clouds", rightList.getX(), 32, 0xFFFFFFFF,true);
        guiGraphics.pose().popMatrix();
    }

    @Override
    public void extractRenderState(GuiGraphicsExtractor guiGraphicsExtractor, int mouseX, int mouseY, float partialTick){
        super.extractRenderState(guiGraphicsExtractor,mouseX,mouseY,partialTick);

    }

    @Override
    public void onClose() {
        List<String> IdentifierToStrings = new ArrayList<>();
        selectedItems.forEach(item->{
            String name = item.getPath();
            if(name.contains("loaded_texture_")){
                name = name.split("loaded_texture_")[1];
                Path ResourcesDir = FMLPaths.GAMEDIR.get().resolve(ResourceFolderName);
                Path Clouds = ResourcesDir.resolve(CloudsFolderName);
                name = Clouds.resolve(name).toString();
            }
            SkyboxMod.LOGGER.debug("Loaded Identifier: " + name);
            IdentifierToStrings.add(name);
        });
        Config.CLOUD_PATHS.get().clear();
        Config.CLOUD_PATHS.set(IdentifierToStrings);
        Config.CLOUD_PATHS.save();
        DistantSkyObject.RegenerateClouds();
        this.minecraft.setScreen(this.lastScreen);
    }

    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
        boolean scroll = false;
        if (leftList != null && leftList.mouseScrolled(mouseX, mouseY, scrollX, scrollY)) {
            scroll =  true;
        }
        if (rightList != null && rightList.mouseScrolled(mouseX, mouseY, scrollX, scrollY)) {
            scroll = true;
        }
        if(scroll) return true;
        return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
    }


    private class SelectionPanelList extends ObjectSelectionList<TextRowEntry> {

        private final SelectionScreen parent;

        public SelectionPanelList(Minecraft minecraft, int width, int height, int y, int itemHeight, SelectionScreen parent) {
            super(minecraft, width, height, y, itemHeight);
            this.parent = parent;
        }
        public void AddEntry(TextRowEntry entry){
            this.addEntry(entry);
        }
        public void RemoveEntry(TextRowEntry entry){
            this.removeEntry(entry);
        }

        @Override
        public int getRowWidth() {
            return getWidth() - this.scrollbarWidth();
        }

        public void ClearChildren(){
            this.clearEntries();
        }

        @Override
        protected int scrollBarX() {
            return this.getX() + this.getRowWidth();
        }

        @Override
        public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY)
        {
            if (!this.visible || !this.isHovered) {
                return false;
            } else {
                this.setScrollAmount(this.scrollAmount() - scrollY * this.scrollRate());
                return true;
            }
        }


    }

    private class TextRowEntry extends ObjectSelectionList.Entry<TextRowEntry> {
        private final Identifier textValue;
        private final Button transferButton;
        private final SelectionScreen Parent;

        public TextRowEntry(Identifier value, boolean isAvailableSide, SelectionScreen Parent) {
            this.Parent = Parent;
            this.textValue = value;

            String buttonSymbol = isAvailableSide ? "➡" : "⬅";
            TextRowEntry currentEntry = this;
            this.transferButton = Button.builder(Component.literal(buttonSymbol), button -> {
                if (isAvailableSide) {
                    availableItems.remove(textValue);
                    selectedItems.add(textValue);
                    Parent.leftList.RemoveEntry(currentEntry);
                } else {
                    selectedItems.remove(textValue);
                    availableItems.add(textValue);
                    Parent.rightList.RemoveEntry(currentEntry);
                }
                SkyboxMod.LOGGER.debug("BUTTON CLICKED!!!! " + isAvailableSide);
                refreshListData();
            }).bounds(0, 0, 20, 20).build();
            transferButtons.add(this.transferButton);
        }

        @Override
        public void extractContent(@NonNull GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean isHovered, float partialTick) {
            int left = this.getX();
            int top = this.getY();
            int rowWidth = this.getWidth();
            int rowHeight = this.getHeight();
            this.transferButton.setX(left + rowWidth - (transferButton.getWidth() + 2));
            this.transferButton.setY(top + rowHeight/2 - transferButton.getWidth()/2);
            this.transferButton.extractRenderState(graphics, mouseX, mouseY, partialTick);
            graphics.pose().pushMatrix();
            graphics.pose().translate((float)left, (float)top);
           // SkyboxMod.LOGGER.debug("\n this font: " + Parent.getFont() + "\n this rowWidth:" + rowWidth + "\n this Text: " + this.textValue + "\n this Position: " + left +"_"+top);
            String name = this.textValue.getPath();
            if(name.contains("loaded_texture_")){
                name = name.split("loaded_texture_")[1];
            }
            graphics.blit( this.textValue,0, 0, 48,  48,0,1,0,1);
            graphics.text(Parent.getFont(), name, 4, 52, 0xFFFFFFFF, true);
            graphics.pose().popMatrix();
        }

        @Override
        public boolean mouseClicked(MouseButtonEvent event, boolean doubleclicked) {
            if (this.transferButton.mouseClicked(event, doubleclicked)) {
                return true;
            }
            return super.mouseClicked(event, doubleclicked);
        }

        @Override
        public Component getNarration() {
            String name = this.textValue.getPath();
            if(name.contains("loaded_texture_")){
                name = name.split("loaded_texture_")[1];
            }
            return Component.literal(name);
        }
    }

}
