package eu.mrneznamy.mrultimatelibrary.gui;

import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import eu.mrneznamy.mrultimatelibrary.MrUltimateLibrary;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * Advanced Form API supporting native Paper Dialogs (1.21.7+)
 * with automatic fallback to Chest/Anvil GUIs on older versions.
 */
public class MrLibForm {

    private final String title;
    private final List<FormElement> elements = new ArrayList<>();
    private Consumer<FormResult> onSubmit;
    private Runnable onCancel;

    public MrLibForm(String title) {
        this.title = title;
    }

    public MrLibForm addText(String id, String label) {
        return addText(id, label, null);
    }

    public MrLibForm addText(String id, String label, String defaultValue) {
        elements.add(new FormElement(id, label, FormElementType.TEXT, defaultValue));
        return this;
    }

    public MrLibForm addCheckbox(String id, String label, boolean defaultValue) {
        elements.add(new FormElement(id, label, FormElementType.CHECKBOX, defaultValue));
        return this;
    }

    public MrLibForm addDropdown(String id, String label, List<String> options) {
        elements.add(new FormElement(id, label, FormElementType.DROPDOWN, options));
        return this;
    }

    public MrLibForm addSlider(String id, String label, float min, float max, float defaultValue) {
        return addSlider(id, label, min, max, defaultValue, 0.01f);
    }

    public MrLibForm addSlider(String id, String label, float min, float max, float defaultValue, float step) {
        elements.add(new FormElement(id, label, FormElementType.SLIDER, new float[]{min, max, defaultValue, step}));
        return this;
    }

    public MrLibForm addMessage(String message) {
        elements.add(new FormElement(null, message, FormElementType.MESSAGE));
        return this;
    }

    public MrLibForm addItem(ItemStack item) {
        elements.add(new FormElement(null, null, FormElementType.ITEM, item));
        return this;
    }

    public MrLibForm onSubmit(Consumer<FormResult> onSubmit) {
        this.onSubmit = onSubmit;
        return this;
    }

    public MrLibForm onCancel(Runnable onCancel) {
        this.onCancel = onCancel;
        return this;
    }

    public void open(Player player) {
        try {
            if (isNativeSupported()) {
                openNative(player);
                return;
            } else {
                Bukkit.getLogger().info("[MrUltimateLibrary] Native Dialogs not supported (Class not found).");
            }
        } catch (Throwable t) {
            Bukkit.getLogger().warning("[MrUltimateLibrary] Error opening native dialog: " + t.getMessage());
            t.printStackTrace();
        }
        
        openFallback(player);
    }

    public static boolean isNativeSupported() {
        try {
            if (Boolean.getBoolean("mrlib.disable.native.dialogs")) {
                return false;
            }
            org.bukkit.plugin.Plugin instance = MrUltimateLibrary.getInstance();
            if (instance != null && !instance.getConfig().getBoolean("use-native-dialogs", true)) {
                return false;
            }

            ClassLoader loader = Bukkit.class.getClassLoader();
            
            Class.forName("io.papermc.paper.dialog.Dialog", false, loader);
            
            
            boolean hasShowDialog = false;
            for (java.lang.reflect.Method m : Player.class.getMethods()) {
                if (m.getName().equals("showDialog") && m.getParameterCount() == 1) {
                    hasShowDialog = true;
                    break;
                }
            }
            return hasShowDialog;
        } catch (Throwable ignored) {
            return false;
        }
    }

    public static void showConfirmation(Player player, String title, String body, Consumer<Boolean> callback) {
        MrLibForm form = new MrLibForm(title)
            .addMessage(body)
            .onSubmit(result -> callback.accept(true))
            .onCancel(() -> callback.accept(false));
        form.open(player);
    }

    public static void showInput(Player player, String title, String body, String defaultValue, Consumer<String> callback) {
        MrLibForm form = new MrLibForm(title)
            .addMessage(body)
            .addText("input", "Value", defaultValue)
            .onSubmit(result -> {
                String val = result.getString("input");
                callback.accept(val != null ? val : "");
            })
            .onCancel(() -> callback.accept(null));
        form.open(player);
    }


    private void openNative(Player player) {
        MrLibFormNative.open(player, title, elements, onSubmit, onCancel);
    }

    private void openFallback(Player player) {
        new MrLibFormFallback(title, elements, onSubmit, onCancel).open(player);
    }

    public enum FormElementType {
        TEXT, CHECKBOX, DROPDOWN, SLIDER, MESSAGE, ITEM
    }

    public static class FormElement {
        public final String id;
        public final String label;
        public final FormElementType type;
        public final Object data;

        public FormElement(String id, String label, FormElementType type) {
            this(id, label, type, null);
        }

        public FormElement(String id, String label, FormElementType type, Object data) {
            this.id = id;
            this.label = label;
            this.type = type;
            this.data = data;
        }
    }

    public static class FormResult {
        private final java.util.Map<String, Object> results = new java.util.HashMap<>();

        public void put(String id, Object value) {
            results.put(id, value);
        }

        public String getString(String id) {
            return (String) results.get(id);
        }

        public boolean getBoolean(String id) {
            Object val = results.get(id);
            return val instanceof Boolean ? (Boolean) val : false;
        }

        public float getFloat(String id) {
            Object val = results.get(id);
            return val instanceof Float ? (Float) val : 0.0f;
        }
    }
}
