package com.tiedup.remake.client.gui.widgets;

import static com.tiedup.remake.client.gui.util.GuiLayoutConstants.*;

import com.tiedup.remake.client.gui.util.GuiColors;
import com.tiedup.remake.client.gui.util.GuiLayoutConstants;
import java.util.function.Consumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Vertical slider widget for adjusting Y position of items.
 * Displays current value and supports mouse drag and scroll wheel.
 *
 */
@OnlyIn(Dist.CLIENT)
public class AdjustmentSlider extends AbstractWidget {

    private float minValue;
    private float maxValue;
    private float value;
    private float step;
    private Consumer<Float> onChange;
    private boolean dragging = false;

    // Visual settings
    private int trackColor = GuiColors.BG_LIGHT;
    private int thumbColor = GuiColors.ACCENT_BROWN;
    private int thumbHighlightColor = GuiColors.ACCENT_TAN;
    private int textColor = GuiColors.TEXT_WHITE;
    private int labelColor = GuiColors.TEXT_GRAY;

    // Layout constants - use centralized values
    private static final int THUMB_WIDTH =
        GuiLayoutConstants.SLIDER_THUMB_WIDTH; // 8px
    private static final int THUMB_HEIGHT =
        GuiLayoutConstants.SLIDER_THUMB_HEIGHT; // 20px
    private static final int TRACK_WIDTH =
        GuiLayoutConstants.SLIDER_TRACK_WIDTH; // 4px

    // Space reserved for labels (top and bottom)
    private static final int LABEL_SPACE = 14;

    /**
     * Create a new adjustment slider.
     *
     * @param x X position
     * @param y Y position
     * @param width Widget width
     * @param height Widget height (includes label space at top and bottom)
     * @param min Minimum value
     * @param max Maximum value
     * @param initial Initial value
     * @param onChange Callback when value changes
     */
    public AdjustmentSlider(
        int x,
        int y,
        int width,
        int height,
        float min,
        float max,
        float initial,
        Consumer<Float> onChange
    ) {
        super(x, y, width, height, Component.empty());
        this.minValue = min;
        this.maxValue = max;
        this.value = Mth.clamp(initial, min, max);
        this.step = 0.25f;
        this.onChange = onChange;
    }

    /**
     * Set the step size for scroll wheel and button adjustments.
     */
    public void setStep(float step) {
        this.step = step;
    }

    /**
     * Get the current value.
     */
    public float getValue() {
        return value;
    }

    /**
     * Set the current value (clamped to range).
     */
    public void setValue(float newValue) {
        float oldValue = this.value;
        this.value = Mth.clamp(newValue, minValue, maxValue);

        if (this.value != oldValue && onChange != null) {
            onChange.accept(this.value);
        }
    }

    /**
     * Increase value by step.
     */
    public void increment() {
        setValue(value + step);
    }

    /**
     * Decrease value by step.
     */
    public void decrement() {
        setValue(value - step);
    }

    /**
     * Reset to center (0.0).
     */
    public void reset() {
        setValue(0.0f);
    }

    @Override
    protected void renderWidget(
        GuiGraphics graphics,
        int mouseX,
        int mouseY,
        float partialTick
    ) {
        Minecraft mc = Minecraft.getInstance();

        // Calculate center X for all elements (ensures perfect alignment)
        int centerX = getX() + width / 2;

        // Track area (excluding label space at top and bottom)
        int trackY = getY() + LABEL_SPACE;
        int trackHeight =
            height - LABEL_SPACE * 2 - GuiLayoutConstants.LINE_HEIGHT; // Leave room for value text

        // Draw track background (centered)
        int trackX = centerX - TRACK_WIDTH / 2;
        graphics.fill(
            trackX,
            trackY,
            trackX + TRACK_WIDTH,
            trackY + trackHeight,
            trackColor
        );

        // Track border for visibility
        graphics.fill(
            trackX - 1,
            trackY,
            trackX,
            trackY + trackHeight,
            GuiColors.darken(trackColor, 0.3f)
        );
        graphics.fill(
            trackX + TRACK_WIDTH,
            trackY,
            trackX + TRACK_WIDTH + 1,
            trackY + trackHeight,
            GuiColors.darken(trackColor, 0.3f)
        );

        // Draw center line marker (zero point)
        if (minValue < 0 && maxValue > 0) {
            float zeroNormalized = (0 - minValue) / (maxValue - minValue);
            int zeroY =
                trackY +
                (int) ((1 - zeroNormalized) * (trackHeight - THUMB_HEIGHT)) +
                THUMB_HEIGHT / 2;
            graphics.fill(
                centerX - THUMB_WIDTH / 2 - 2,
                zeroY - 1,
                centerX + THUMB_WIDTH / 2 + 2,
                zeroY + 1,
                GuiColors.BORDER_LIGHT
            );
        }

        // Thumb position (inverted because Y+ is down in screen space)
        float normalized = (value - minValue) / (maxValue - minValue);
        int thumbY =
            trackY + (int) ((1 - normalized) * (trackHeight - THUMB_HEIGHT));
        int thumbX = centerX - THUMB_WIDTH / 2; // Centered on same axis as track

        // Draw thumb
        boolean hovered = isMouseOver(mouseX, mouseY);
        int currentThumbColor = (dragging || hovered)
            ? thumbHighlightColor
            : thumbColor;

        // Thumb shadow
        graphics.fill(
            thumbX + 1,
            thumbY + 1,
            thumbX + THUMB_WIDTH + 1,
            thumbY + THUMB_HEIGHT + 1,
            GuiColors.darken(currentThumbColor, 0.5f)
        );

        // Thumb main body
        graphics.fill(
            thumbX,
            thumbY,
            thumbX + THUMB_WIDTH,
            thumbY + THUMB_HEIGHT,
            currentThumbColor
        );

        // Thumb highlight edge (top)
        graphics.fill(
            thumbX,
            thumbY,
            thumbX + THUMB_WIDTH,
            thumbY + 1,
            GuiColors.lighten(currentThumbColor, 0.3f)
        );

        // Thumb center grip lines
        int gripY = thumbY + THUMB_HEIGHT / 2;
        graphics.fill(
            thumbX + 2,
            gripY - 2,
            thumbX + THUMB_WIDTH - 2,
            gripY - 1,
            GuiColors.darken(currentThumbColor, 0.2f)
        );
        graphics.fill(
            thumbX + 2,
            gripY + 1,
            thumbX + THUMB_WIDTH - 2,
            gripY + 2,
            GuiColors.darken(currentThumbColor, 0.2f)
        );

        // Draw max label at top (within widget bounds)
        String maxStr = String.format("+%.1f", maxValue);
        int maxTextWidth = mc.font.width(maxStr);
        graphics.drawString(
            mc.font,
            maxStr,
            centerX - maxTextWidth / 2,
            getY() + 2,
            labelColor
        );

        // Draw min label at bottom (within widget bounds)
        String minStr = String.format("%.1f", minValue);
        int minTextWidth = mc.font.width(minStr);
        graphics.drawString(
            mc.font,
            minStr,
            centerX - minTextWidth / 2,
            trackY + trackHeight + 2,
            labelColor
        );

        // Draw current value text (below min label)
        String valueStr = String.format("%.2f", value);
        int valueTextWidth = mc.font.width(valueStr);
        int valueColor =
            Math.abs(value) < 0.01f ? GuiColors.TEXT_GRAY : textColor;
        graphics.drawString(
            mc.font,
            valueStr,
            centerX - valueTextWidth / 2,
            getY() + height - GuiLayoutConstants.LINE_HEIGHT,
            valueColor
        );
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        if (isMouseOver(mouseX, mouseY) && button == 0) {
            dragging = true;
            updateValueFromMouse(mouseY);
            return true;
        }
        return false;
    }

    @Override
    public boolean mouseReleased(double mouseX, double mouseY, int button) {
        if (button == 0) {
            dragging = false;
        }
        return super.mouseReleased(mouseX, mouseY, button);
    }

    @Override
    public boolean mouseDragged(
        double mouseX,
        double mouseY,
        int button,
        double dragX,
        double dragY
    ) {
        if (dragging && button == 0) {
            updateValueFromMouse(mouseY);
            return true;
        }
        return false;
    }

    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        if (isMouseOver(mouseX, mouseY)) {
            // Scroll up = increase value (positive delta)
            setValue(value + (float) delta * step);
            return true;
        }
        return false;
    }

    /**
     * Update value based on mouse Y position.
     */
    private void updateValueFromMouse(double mouseY) {
        // Calculate track area
        int trackY = getY() + LABEL_SPACE;
        int trackHeight =
            height - LABEL_SPACE * 2 - GuiLayoutConstants.LINE_HEIGHT;

        // Account for thumb height
        float usableHeight = trackHeight - THUMB_HEIGHT;
        float relativeY = (float) (mouseY - trackY - THUMB_HEIGHT / 2.0);

        // Invert because screen Y increases downward
        float normalized = 1 - Mth.clamp(relativeY / usableHeight, 0, 1);

        float newValue = minValue + normalized * (maxValue - minValue);

        // Optionally snap to step
        newValue = Math.round(newValue / step) * step;

        setValue(newValue);
    }

    /**
     * Get the recommended widget height including labels.
     * Use this when creating the slider to ensure proper sizing.
     */
    public static int getRecommendedHeight(int trackHeight) {
        return trackHeight + LABEL_SPACE * 2 + GuiLayoutConstants.LINE_HEIGHT;
    }

    @Override
    protected void updateWidgetNarration(NarrationElementOutput output) {
        output.add(
            NarratedElementType.TITLE,
            Component.translatable("gui.tiedup.adjustment_slider", value)
        );
    }
}
