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

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

import com.tiedup.remake.client.gui.util.GuiColors;
import com.tiedup.remake.client.gui.widgets.AdjustmentSlider;
import com.tiedup.remake.client.gui.widgets.EntityPreviewWidget;
import com.tiedup.remake.items.base.AdjustmentHelper;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Base class for adjustment screens (player self and remote slave adjustment).
 * Refactored to use new BaseScreen architecture.
 */
@OnlyIn(Dist.CLIENT)
public abstract class BaseAdjustmentScreen extends BaseScreen {

    /**
     * Adjustment mode - which item(s) to adjust.
     */
    protected enum Mode {
        GAG,
        BLINDFOLD,
        BOTH,
    }

    // Current state
    protected Mode currentMode = Mode.GAG;
    protected float currentValue = 0.0f;
    protected float currentScaleValue = AdjustmentHelper.DEFAULT_SCALE;

    // Widgets
    protected EntityPreviewWidget preview;
    protected AdjustmentSlider slider;
    protected Button gagButton;
    protected Button blindfoldButton;
    protected Button bothButton;
    protected Button resetButton;
    protected Button decrementButton;
    protected Button incrementButton;
    protected Button scaleDecrementButton;
    protected Button scaleIncrementButton;
    protected Button scaleResetButton;
    protected Button doneButton;

    // Selected mode indicator colors
    private static final int TAB_SELECTED = GuiColors.ACCENT_BROWN;

    protected BaseAdjustmentScreen(Component title) {
        super(title);
    }

    @Override
    protected int getPreferredWidth() {
        // Target: ~320px
        return 320;
    }

    @Override
    protected int getPreferredHeight() {
        // Target: ~290px (extra row for scale controls)
        return 290;
    }

    // ==================== ABSTRACT METHODS ====================

    protected abstract LivingEntity getTargetEntity();

    protected abstract ItemStack getGag();

    protected abstract ItemStack getBlindfold();

    protected abstract void sendAdjustment(Mode mode, float value, float scale);

    protected String getExtraInfo() {
        return null;
    }

    // ==================== INITIALIZATION ====================

    @Override
    protected void init() {
        super.init();

        // Determine initial mode based on what's equipped
        if (getGag().isEmpty() && !getBlindfold().isEmpty()) {
            currentMode = Mode.BLINDFOLD;
        }

        // Load current adjustment value
        loadCurrentValue();

        setupPreview();
        setupSlider();
        setupModeTabs();
        setupActionButtons();
        setupScaleButtons();
        setupDoneButton();

        updateButtonStates();
    }

    private void setupPreview() {
        // Preview on left side of panel
        int previewX = this.leftPos + MARGIN_L;
        int previewY = this.topPos + TITLE_HEIGHT + MARGIN_M;
        int previewWidth = 120; // Fixed width for preview area
        int previewHeight = 140;

        LivingEntity entity = getTargetEntity();
        if (entity != null) {
            preview = new EntityPreviewWidget(
                previewX,
                previewY,
                previewWidth,
                previewHeight,
                entity
            );
            preview.setAutoRotate(false);
            this.addRenderableWidget(preview);
        }
    }

    private void setupSlider() {
        // Slider on right side of panel
        int sliderWidth = 40;
        int sliderX =
            this.leftPos + this.imageWidth - sliderWidth - MARGIN_L - 10;
        int sliderY = this.topPos + TITLE_HEIGHT + MARGIN_M;
        int sliderHeight = AdjustmentSlider.getRecommendedHeight(120);

        slider = new AdjustmentSlider(
            sliderX,
            sliderY,
            sliderWidth,
            sliderHeight,
            -4.0f,
            4.0f,
            currentValue,
            this::onSliderChanged
        );
        this.addRenderableWidget(slider);
    }

    private void setupModeTabs() {
        // Mode tabs below preview and slider area
        int tabY = this.topPos + TITLE_HEIGHT + 140 + 10; // Below preview
        int tabWidth = 60;
        int totalTabsWidth = tabWidth * 3 + MARGIN_S * 2;
        int tabStartX = this.leftPos + (this.imageWidth - totalTabsWidth) / 2;

        gagButton = Button.builder(
            Component.translatable("gui.tiedup.tab.gag"),
            b -> setMode(Mode.GAG)
        )
            .bounds(tabStartX, tabY, tabWidth, BUTTON_HEIGHT)
            .build();
        this.addRenderableWidget(gagButton);

        blindfoldButton = Button.builder(
            Component.translatable("gui.tiedup.tab.blindfold"),
            b -> setMode(Mode.BLINDFOLD)
        )
            .bounds(
                tabStartX + tabWidth + MARGIN_S,
                tabY,
                tabWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(blindfoldButton);

        bothButton = Button.builder(
            Component.translatable("gui.tiedup.tab.both"),
            b -> setMode(Mode.BOTH)
        )
            .bounds(
                tabStartX + (tabWidth + MARGIN_S) * 2,
                tabY,
                tabWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(bothButton);
    }

    private void setupActionButtons() {
        // Action buttons below tabs
        int actionY = gagButton.getY() + BUTTON_HEIGHT + MARGIN_S;
        int buttonWidth = 45;
        int totalWidth = buttonWidth * 3 + MARGIN_S * 2;
        int actionStartX = this.leftPos + (this.imageWidth - totalWidth) / 2;

        resetButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.reset"), b -> resetValue())
            .bounds(actionStartX, actionY, buttonWidth, BUTTON_HEIGHT)
            .build();
        this.addRenderableWidget(resetButton);

        decrementButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.decrement"), b ->
            slider.decrement()
        )
            .bounds(
                actionStartX + buttonWidth + MARGIN_S,
                actionY,
                buttonWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(decrementButton);

        incrementButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.increment"), b ->
            slider.increment()
        )
            .bounds(
                actionStartX + (buttonWidth + MARGIN_S) * 2,
                actionY,
                buttonWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(incrementButton);
    }

    private void setupScaleButtons() {
        // Scale controls below position action buttons
        int scaleY = incrementButton.getY() + BUTTON_HEIGHT + MARGIN_S;
        int buttonWidth = 45;
        int totalWidth = buttonWidth * 3 + MARGIN_S * 2;
        int scaleStartX = this.leftPos + (this.imageWidth - totalWidth) / 2;

        scaleResetButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.scale_reset"), b ->
            applyScale(AdjustmentHelper.DEFAULT_SCALE)
        )
            .bounds(scaleStartX, scaleY, buttonWidth, BUTTON_HEIGHT)
            .build();
        this.addRenderableWidget(scaleResetButton);

        scaleDecrementButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.scale_decrement"), b ->
            applyScale(currentScaleValue - AdjustmentHelper.SCALE_STEP)
        )
            .bounds(
                scaleStartX + buttonWidth + MARGIN_S,
                scaleY,
                buttonWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(scaleDecrementButton);

        scaleIncrementButton = Button.builder(Component.translatable("gui.tiedup.adjustment.btn.scale_increment"), b ->
            applyScale(currentScaleValue + AdjustmentHelper.SCALE_STEP)
        )
            .bounds(
                scaleStartX + (buttonWidth + MARGIN_S) * 2,
                scaleY,
                buttonWidth,
                BUTTON_HEIGHT
            )
            .build();
        this.addRenderableWidget(scaleIncrementButton);
    }

    private void setupDoneButton() {
        // Done button at bottom
        int doneX = this.leftPos + (this.imageWidth - BUTTON_WIDTH_L) / 2;
        int doneY = this.topPos + this.imageHeight - BUTTON_HEIGHT - MARGIN_M;

        doneButton = Button.builder(
            Component.translatable("gui.tiedup.done"),
            b -> onClose()
        )
            .bounds(doneX, doneY, BUTTON_WIDTH_L, BUTTON_HEIGHT)
            .build();
        this.addRenderableWidget(doneButton);
    }

    // ==================== LOGIC ====================

    protected void loadCurrentValue() {
        ItemStack stack = switch (currentMode) {
            case GAG -> getGag();
            case BLINDFOLD -> getBlindfold();
            case BOTH -> {
                ItemStack gag = getGag();
                yield gag.isEmpty() ? getBlindfold() : gag;
            }
        };

        if (!stack.isEmpty()) {
            currentValue = AdjustmentHelper.getAdjustment(stack);
            currentScaleValue = AdjustmentHelper.getScale(stack);
        } else {
            currentValue = 0.0f;
            currentScaleValue = AdjustmentHelper.DEFAULT_SCALE;
        }
        if (slider != null) {
            slider.setValue(currentValue);
        }
    }

    private void onSliderChanged(float newValue) {
        this.currentValue = newValue;
        applyAdjustment(newValue);
        if (preview != null) {
            preview.refresh();
        }
    }

    protected void applyAdjustment(float value) {
        switch (currentMode) {
            case GAG -> {
                ItemStack gag = getGag();
                if (!gag.isEmpty()) {
                    AdjustmentHelper.setAdjustment(gag, value);
                    AdjustmentHelper.setScale(gag, currentScaleValue);
                    sendAdjustment(Mode.GAG, value, currentScaleValue);
                }
            }
            case BLINDFOLD -> {
                ItemStack blind = getBlindfold();
                if (!blind.isEmpty()) {
                    AdjustmentHelper.setAdjustment(blind, value);
                    AdjustmentHelper.setScale(blind, currentScaleValue);
                    sendAdjustment(Mode.BLINDFOLD, value, currentScaleValue);
                }
            }
            case BOTH -> {
                ItemStack gag = getGag();
                ItemStack blind = getBlindfold();
                if (!gag.isEmpty()) {
                    AdjustmentHelper.setAdjustment(gag, value);
                    AdjustmentHelper.setScale(gag, currentScaleValue);
                    sendAdjustment(Mode.GAG, value, currentScaleValue);
                }
                if (!blind.isEmpty()) {
                    AdjustmentHelper.setAdjustment(blind, value);
                    AdjustmentHelper.setScale(blind, currentScaleValue);
                    sendAdjustment(Mode.BLINDFOLD, value, currentScaleValue);
                }
            }
        }
    }

    protected void applyScale(float scale) {
        this.currentScaleValue = Mth.clamp(
            scale,
            AdjustmentHelper.MIN_SCALE,
            AdjustmentHelper.MAX_SCALE
        );
        // Re-apply both values together (scale changed, position stays)
        applyAdjustment(currentValue);
        if (preview != null) {
            preview.refresh();
        }
    }

    protected void setMode(Mode mode) {
        this.currentMode = mode;
        loadCurrentValue();
        updateButtonStates();
    }

    protected void resetValue() {
        if (slider != null) {
            slider.setValue(0.0f);
        }
    }

    protected void updateButtonStates() {
        boolean hasGag = !getGag().isEmpty();
        boolean hasBlind = !getBlindfold().isEmpty();

        if (gagButton != null) gagButton.active = hasGag;
        if (blindfoldButton != null) blindfoldButton.active = hasBlind;
        if (bothButton != null) bothButton.active = hasGag || hasBlind;
    }

    // ==================== RENDERING ====================

    @Override
    public void render(
        GuiGraphics graphics,
        int mouseX,
        int mouseY,
        float partialTick
    ) {
        super.render(graphics, mouseX, mouseY, partialTick);

        // Draw selected mode indicator
        renderModeIndicator(graphics);

        // Extra info (e.g., slave name)
        String extraInfo = getExtraInfo();
        if (extraInfo != null) {
            graphics.drawCenteredString(
                this.font,
                extraInfo,
                this.leftPos + this.imageWidth / 2,
                this.topPos + TITLE_HEIGHT - 2,
                GuiColors.ACCENT_TAN
            );
        }

        // Scale label above scale buttons
        if (scaleResetButton != null) {
            String scaleLabel =
                Component.translatable(
                    "gui.tiedup.adjustment.scale"
                ).getString() +
                ": " +
                String.format("%.1fx", currentScaleValue);
            graphics.drawCenteredString(
                this.font,
                scaleLabel,
                this.leftPos + this.imageWidth / 2,
                scaleResetButton.getY() - 10,
                GuiColors.TEXT_GRAY
            );
        }

        // Current item info
        String itemInfo = getCurrentItemInfo();
        graphics.drawCenteredString(
            this.font,
            itemInfo,
            this.leftPos + this.imageWidth / 2,
            this.topPos + this.imageHeight - BUTTON_HEIGHT - MARGIN_L - 10,
            GuiColors.TEXT_GRAY
        );
    }

    private void renderModeIndicator(GuiGraphics graphics) {
        Button selectedButton = switch (currentMode) {
            case GAG -> gagButton;
            case BLINDFOLD -> blindfoldButton;
            case BOTH -> bothButton;
        };

        if (selectedButton != null) {
            int indicatorY = selectedButton.getY() + selectedButton.getHeight();
            graphics.fill(
                selectedButton.getX() + 2,
                indicatorY,
                selectedButton.getX() + selectedButton.getWidth() - 2,
                indicatorY + 2,
                TAB_SELECTED
            );
        }
    }

    protected String getCurrentItemInfo() {
        return switch (currentMode) {
            case GAG -> {
                ItemStack gag = getGag();
                yield gag.isEmpty()
                    ? Component.translatable(
                          "gui.tiedup.adjustment.no_gag"
                      ).getString()
                    : gag.getHoverName().getString();
            }
            case BLINDFOLD -> {
                ItemStack blind = getBlindfold();
                yield blind.isEmpty()
                    ? Component.translatable(
                          "gui.tiedup.adjustment.no_blindfold"
                      ).getString()
                    : blind.getHoverName().getString();
            }
            case BOTH -> Component.translatable(
                "gui.tiedup.adjustment.both"
            ).getString();
        };
    }
}
