package com.straice.smoothdoors.client.ui;

import com.straice.smoothdoors.config.SddConfig;
import com.straice.smoothdoors.config.SddConfigManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.client.gui.widget.ThreePartsLayoutWidget;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.Text;

import java.util.List;
import java.util.Locale;

public class SddConfigScreen extends Screen {
    private static final int ITEM_HEIGHT = 24;
    private static final int ROW_WIDTH = 310;
    private static final int COLUMN_WIDTH = 150;
    private static final int COLUMN_GAP = 10;
    private static final int GROUP_GAP = 10;

    private final Screen parent;
    private final SddConfig cfg;
    private final ThreePartsLayoutWidget layout = new ThreePartsLayoutWidget(this);
    private SettingsList list;

    public SddConfigScreen(Screen parent) {
        super(Text.literal("Smooth Double Doors - Settings"));
        this.parent = parent;
        this.cfg = SddConfigManager.get();
    }

    @Override
    protected void init() {
        initHeader();
        initBody();
        initFooter();

        layout.forEachChild(this::addDrawableChild);
        refreshWidgetPositions();
    }

    private void initHeader() {
        layout.addHeader(this.title, this.textRenderer);
    }

    private void initBody() {
        if (this.client == null) return;
        list = layout.addBody(new SettingsList(this.client, this.width, layout));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Double Doors: " + (cfg.connectDoors ? "ON" : "OFF"),
                        () -> cfg.connectDoors = !cfg.connectDoors),
                toggle(COLUMN_WIDTH, () -> "Redstone Activable: " + (cfg.redstoneDoubleDoors ? "ON" : "OFF"),
                        () -> cfg.redstoneDoubleDoors = !cfg.redstoneDoubleDoors)
        ));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Door Animation: " + (cfg.animateDoors ? "ON" : "OFF"),
                        () -> cfg.animateDoors = !cfg.animateDoors),
                new SpeedSlider(COLUMN_WIDTH, "Animation Speed", cfg.doorSpeed, v -> {
                    cfg.doorSpeed = v;
                    SddConfigManager.save();
                })
        ));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Double Trapdoors: " + (cfg.connectTrapdoors ? "ON" : "OFF"),
                        () -> cfg.connectTrapdoors = !cfg.connectTrapdoors),
                toggle(COLUMN_WIDTH, () -> "Redstone Activable: " + (cfg.redstoneDoubleTrapdoors ? "ON" : "OFF"),
                        () -> cfg.redstoneDoubleTrapdoors = !cfg.redstoneDoubleTrapdoors),
                GROUP_GAP
        ));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Trapdoor Animation: " + (cfg.animateTrapdoors ? "ON" : "OFF"),
                        () -> cfg.animateTrapdoors = !cfg.animateTrapdoors),
                new SpeedSlider(COLUMN_WIDTH, "Animation Speed", cfg.trapdoorSpeed, v -> {
                    cfg.trapdoorSpeed = v;
                    SddConfigManager.save();
                }),
                GROUP_GAP
        ));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Double Fence Gates: " + (cfg.connectFenceGates ? "ON" : "OFF"),
                        () -> cfg.connectFenceGates = !cfg.connectFenceGates),
                toggle(COLUMN_WIDTH, () -> "Redstone Activable: " + (cfg.redstoneDoubleFenceGates ? "ON" : "OFF"),
                        () -> cfg.redstoneDoubleFenceGates = !cfg.redstoneDoubleFenceGates),
                GROUP_GAP * 2
        ));

        list.addEntry(new SettingsEntry(
                toggle(COLUMN_WIDTH, () -> "Fence Gate Animation: " + (cfg.animateFenceGates ? "ON" : "OFF"),
                        () -> cfg.animateFenceGates = !cfg.animateFenceGates),
                new SpeedSlider(COLUMN_WIDTH, "Animation Speed", cfg.fenceGateSpeed, v -> {
                    cfg.fenceGateSpeed = v;
                    SddConfigManager.save();
                }),
                GROUP_GAP * 2
        ));
    }

    private void initFooter() {
        layout.addFooter(ButtonWidget.builder(ScreenTexts.DONE, btn -> {
            SddConfigManager.save();
            if (this.client != null) this.client.setScreen(parent);
        }).width(200).build());
    }

    @Override
    protected void refreshWidgetPositions() {
        layout.refreshPositions();
        if (list != null) {
            list.position(this.width, layout);
        }
    }

    @Override
    public void close() {
        SddConfigManager.save();
        if (this.client != null) this.client.setScreen(parent);
    }

    private ButtonWidget toggle(int width, java.util.function.Supplier<String> label, Runnable action) {
        return ButtonWidget.builder(Text.literal(label.get()), btn -> {
            action.run();
            btn.setMessage(Text.literal(label.get()));
            SddConfigManager.save();
        }).dimensions(0, 0, width, 20).build();
    }

    private static final class SettingsList extends ElementListWidget<SettingsEntry> {
        SettingsList(MinecraftClient client, int width, ThreePartsLayoutWidget layout) {
            super(client, width, layout.getContentHeight(), layout.getHeaderHeight(), ITEM_HEIGHT);
            this.centerListVertically = false;
        }

        @Override
        public int addEntry(SettingsEntry entry) {
            return super.addEntry(entry);
        }

        @Override
        public int getRowWidth() {
            return ROW_WIDTH;
        }
    }

    private static final class SettingsEntry extends ElementListWidget.Entry<SettingsEntry> {
        private final ClickableWidget left;
        private final ClickableWidget right;
        private final List<ClickableWidget> widgets;
        private final int topPadding;

        SettingsEntry(ClickableWidget left, ClickableWidget right) {
            this(left, right, 0);
        }

        SettingsEntry(ClickableWidget left, ClickableWidget right, int topPadding) {
            this.left = left;
            this.right = right;
            this.topPadding = topPadding;
            if (left == null && right == null) {
                this.widgets = List.of();
            } else if (right == null) {
                this.widgets = List.of(left);
            } else {
                this.widgets = List.of(left, right);
            }
        }

        @Override
        public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight,
                           int mouseX, int mouseY, boolean hovered, float delta) {
            if (left == null && right == null) {
                return;
            }
            if (right == null) {
                if (left == null) return;
                left.setX(x);
                left.setY(y + topPadding);
                left.render(context, mouseX, mouseY, delta);
                return;
            }

            int leftX = x;
            int rightX = x + COLUMN_WIDTH + COLUMN_GAP;
            left.setX(leftX);
            left.setY(y + topPadding);
            right.setX(rightX);
            right.setY(y + topPadding);
            left.render(context, mouseX, mouseY, delta);
            right.render(context, mouseX, mouseY, delta);
        }

        @Override
        public List<? extends Element> children() {
            return widgets;
        }

        @Override
        public List<? extends Selectable> selectableChildren() {
            return widgets;
        }
    }


    private static class SpeedSlider extends SliderWidget {
        private final String label;
        private final java.util.function.Consumer<Float> onApply;

        private static float toSpeed(double v) { return (float) (0.2 + v * 2.8); }
        private static double toValue(float speed) {
            double v = (speed - 0.2) / 2.8;
            if (v < 0) v = 0;
            if (v > 1) v = 1;
            return v;
        }

        SpeedSlider(int width, String label, float speed,
                    java.util.function.Consumer<Float> onApply) {
            super(0, 0, width, 20, Text.literal(label), toValue(speed));
            this.label = label;
            this.onApply = onApply;
            updateMessage();
        }

        @Override
        protected void updateMessage() {
            float sp = toSpeed(this.value);
            setMessage(Text.literal(label + ": " + String.format(Locale.ROOT, "%.2f", sp) + "x"));
        }

        @Override
        protected void applyValue() {
            onApply.accept(toSpeed(this.value));
        }
    }
}
