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

import com.tiedup.remake.client.gui.util.GuiRenderUtil;
import com.tiedup.remake.items.base.IHasResistance;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.minecraft.ChatFormatting;
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.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * V2 widget representing a single body region equipment slot.
 * Uses {@link BodyRegionV2} for body region mapping.
 *
 * Epic 6A: V2 migration of BondageSlotWidget.
 */
@OnlyIn(Dist.CLIENT)
public class RegionSlotWidget extends AbstractWidget {

    private final BodyRegionV2 region;
    private final Supplier<ItemStack> itemGetter;
    private Consumer<RegionSlotWidget> onClick;
    private Consumer<RegionSlotWidget> onAdjustClick;
    private Consumer<RegionSlotWidget> onRemoveClick;
    private Consumer<RegionSlotWidget> onEquipClick;

    // Visual settings
    private boolean showAdjustButton = false;
    private boolean showRemoveButton = false;
    private boolean showEquipButton = false;
    private boolean selected = false;

    // Layout constants
    private static final int ICON_SIZE = 16;
    private static final int PADDING = 4;
    private static final int ADJUST_BUTTON_SIZE = 14;
    private static final int REMOVE_BUTTON_SIZE = 14;
    private static final int EQUIP_BUTTON_WIDTH = 50;
    private static final int EQUIP_BUTTON_HEIGHT = 16;
    private static final int RESISTANCE_BAR_WIDTH = 50;
    private static final int RESISTANCE_BAR_HEIGHT = 4;

    /**
     * Create a new region slot widget.
     *
     * @param x X position
     * @param y Y position
     * @param width Widget width
     * @param height Widget height
     * @param region The V2 body region
     * @param itemGetter Supplier that returns the current ItemStack in this region
     */
    public RegionSlotWidget(
        int x,
        int y,
        int width,
        int height,
        BodyRegionV2 region,
        Supplier<ItemStack> itemGetter
    ) {
        super(
            x,
            y,
            width,
            height,
            Component.translatable(
                "gui.tiedup.region." + region.name().toLowerCase()
            )
        );
        this.region = region;
        this.itemGetter = itemGetter;
    }

    /**
     * Set click handler for the main slot area.
     */
    public void setOnClick(Consumer<RegionSlotWidget> onClick) {
        this.onClick = onClick;
    }

    /**
     * Set click handler for the adjust button.
     */
    public void setOnAdjustClick(Consumer<RegionSlotWidget> onAdjustClick) {
        this.onAdjustClick = onAdjustClick;
    }

    /**
     * Enable/disable the adjust button (for gags/blindfolds).
     */
    public void setShowAdjustButton(boolean show) {
        this.showAdjustButton = show;
    }

    /**
     * Set click handler for the remove button.
     */
    public void setOnRemoveClick(Consumer<RegionSlotWidget> onRemoveClick) {
        this.onRemoveClick = onRemoveClick;
    }

    /**
     * Enable/disable the remove button.
     */
    public void setShowRemoveButton(boolean show) {
        this.showRemoveButton = show;
    }

    /**
     * Set click handler for the equip button (shown for empty slots).
     */
    public void setOnEquipClick(Consumer<RegionSlotWidget> onEquipClick) {
        this.onEquipClick = onEquipClick;
    }

    /**
     * Enable/disable the equip button for empty slots.
     */
    public void setShowEquipButton(boolean show) {
        this.showEquipButton = show;
    }

    /**
     * Set selected state.
     */
    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    /**
     * Get the body region.
     */
    public BodyRegionV2 getRegion() {
        return region;
    }

    /**
     * Get the current item in this region.
     */
    public ItemStack getItem() {
        return itemGetter.get();
    }

    /**
     * Check if adjust button is being hovered.
     */
    private boolean isAdjustButtonHovered(double mouseX, double mouseY) {
        if (!showAdjustButton) return false;

        int buttonX = getAdjustButtonX();
        int buttonY = getY() + (height - ADJUST_BUTTON_SIZE) / 2;

        return (
            mouseX >= buttonX &&
            mouseX < buttonX + ADJUST_BUTTON_SIZE &&
            mouseY >= buttonY &&
            mouseY < buttonY + ADJUST_BUTTON_SIZE
        );
    }

    /**
     * Check if remove button is being hovered.
     */
    private boolean isRemoveButtonHovered(double mouseX, double mouseY) {
        if (!showRemoveButton) return false;

        int buttonX = getRemoveButtonX();
        int buttonY = getY() + (height - REMOVE_BUTTON_SIZE) / 2;

        return (
            mouseX >= buttonX &&
            mouseX < buttonX + REMOVE_BUTTON_SIZE &&
            mouseY >= buttonY &&
            mouseY < buttonY + REMOVE_BUTTON_SIZE
        );
    }

    /**
     * Get X position for adjust button.
     */
    private int getAdjustButtonX() {
        if (showRemoveButton) {
            return (
                getX() +
                width -
                ADJUST_BUTTON_SIZE -
                PADDING -
                REMOVE_BUTTON_SIZE -
                PADDING
            );
        }
        return getX() + width - ADJUST_BUTTON_SIZE - PADDING;
    }

    /**
     * Get X position for remove button (always rightmost).
     */
    private int getRemoveButtonX() {
        return getX() + width - REMOVE_BUTTON_SIZE - PADDING;
    }

    /**
     * Get X position for the equip button (right-aligned in empty slot).
     */
    private int getEquipButtonX() {
        return getX() + width - EQUIP_BUTTON_WIDTH - PADDING;
    }

    /**
     * Get Y position for the equip button (centered vertically).
     */
    private int getEquipButtonY() {
        return getY() + (height - EQUIP_BUTTON_HEIGHT) / 2;
    }

    /**
     * Check if the equip button is being hovered.
     */
    private boolean isEquipButtonHovered(double mouseX, double mouseY) {
        if (!showEquipButton || !itemGetter.get().isEmpty()) return false;
        int bx = getEquipButtonX();
        int by = getEquipButtonY();
        return (
            mouseX >= bx &&
            mouseX < bx + EQUIP_BUTTON_WIDTH &&
            mouseY >= by &&
            mouseY < by + EQUIP_BUTTON_HEIGHT
        );
    }

    @Override
    protected void renderWidget(
        GuiGraphics graphics,
        int mouseX,
        int mouseY,
        float partialTick
    ) {
        Minecraft mc = Minecraft.getInstance();
        ItemStack stack = itemGetter.get();
        boolean hasItem = !stack.isEmpty();
        boolean hovered = isMouseOver(mouseX, mouseY);
        boolean adjustHovered = isAdjustButtonHovered(mouseX, mouseY);
        boolean removeHovered = isRemoveButtonHovered(mouseX, mouseY);
        boolean equipHovered = isEquipButtonHovered(mouseX, mouseY);
        boolean anyButtonHovered =
            adjustHovered || removeHovered || equipHovered;

        // MC-style sunken slot background
        GuiRenderUtil.drawMCSlot(graphics, getX(), getY(), width, height);

        // Selected: gold highlight border on top of the slot
        if (selected) {
            GuiRenderUtil.drawSelectedBorder(
                graphics,
                getX(),
                getY(),
                width,
                height
            );
        }

        // Hover overlay (vanilla white semi-transparent)
        if (hovered && !anyButtonHovered && !selected) {
            GuiRenderUtil.drawSlotHover(
                graphics,
                getX(),
                getY(),
                width,
                height
            );
        }

        // Region icon (uniform dark gray square)
        int iconX = getX() + PADDING;
        int iconY = getY() + (height - ICON_SIZE) / 2;
        graphics.fill(
            iconX,
            iconY,
            iconX + ICON_SIZE,
            iconY + ICON_SIZE,
            0xFF555555
        );

        // Region label
        String typeLabel = getSlotLabel();
        int labelX = iconX + ICON_SIZE + PADDING;
        int labelY = getY() + PADDING;
        graphics.drawString(
            mc.font,
            typeLabel,
            labelX,
            labelY,
            GuiRenderUtil.MC_TEXT_GRAY,
            false
        );

        // Item name or "(empty)"
        Component itemText;
        int itemTextColor;
        if (hasItem) {
            itemText = stack.getHoverName();
            itemTextColor = GuiRenderUtil.MC_TEXT_DARK;
        } else {
            itemText = Component.translatable("gui.tiedup.empty").withStyle(
                ChatFormatting.ITALIC
            );
            itemTextColor = 0xFF808080;
        }

        int textY = labelY + mc.font.lineHeight + 2;
        int maxTextWidth = width - ICON_SIZE - PADDING * 3;
        if (showAdjustButton && hasItem) {
            maxTextWidth -= ADJUST_BUTTON_SIZE + PADDING;
        }
        if (showRemoveButton && hasItem) {
            maxTextWidth -= REMOVE_BUTTON_SIZE + PADDING;
        }

        // Trim text if too long
        String trimmedText = mc.font.plainSubstrByWidth(
            itemText.getString(),
            maxTextWidth
        );
        graphics.drawString(
            mc.font,
            trimmedText,
            labelX,
            textY,
            itemTextColor,
            false
        );

        // Resistance bar (for items that implement IHasResistance)
        if (
            hasItem && stack.getItem() instanceof IHasResistance resistanceItem
        ) {
            Player player = mc.player;
            if (player != null) {
                int current = resistanceItem.getCurrentResistance(
                    stack,
                    player
                );
                int base = resistanceItem.getBaseResistance(player);
                if (base > 0) {
                    float ratio = Math.max(
                        0f,
                        Math.min(1f, (float) current / base)
                    );
                    int barX = getX() + width - RESISTANCE_BAR_WIDTH - PADDING;
                    int barY =
                        getY() + height - RESISTANCE_BAR_HEIGHT - PADDING;
                    // Sunken bar background
                    graphics.fill(
                        barX,
                        barY,
                        barX + RESISTANCE_BAR_WIDTH,
                        barY + RESISTANCE_BAR_HEIGHT,
                        0xFF373737
                    );
                    // Colored fill: red below 30%, green otherwise
                    int fillColor = (ratio < 0.30f) ? 0xFFFF4444 : 0xFF44CC44;
                    int fillWidth = Math.round(RESISTANCE_BAR_WIDTH * ratio);
                    if (fillWidth > 0) {
                        graphics.fill(
                            barX,
                            barY,
                            barX + fillWidth,
                            barY + RESISTANCE_BAR_HEIGHT,
                            fillColor
                        );
                    }
                }
            }
        }

        // Equip button for empty slots (MC-style button)
        if (!hasItem && showEquipButton) {
            int bx = getEquipButtonX();
            int by = getEquipButtonY();
            GuiRenderUtil.drawMCButton(
                graphics,
                bx,
                by,
                EQUIP_BUTTON_WIDTH,
                EQUIP_BUTTON_HEIGHT,
                equipHovered,
                true
            );
            String equipLabel = Component.translatable(
                "gui.tiedup.equip"
            ).getString();
            GuiRenderUtil.drawCenteredStringNoShadow(
                graphics,
                mc.font,
                equipLabel,
                bx + EQUIP_BUTTON_WIDTH / 2,
                by + (EQUIP_BUTTON_HEIGHT - mc.font.lineHeight) / 2,
                GuiRenderUtil.MC_TEXT_DARK
            );
        }

        // Adjust button (for gags/blindfolds) — MC-style small button
        if (showAdjustButton && hasItem) {
            int buttonX = getAdjustButtonX();
            int buttonY = getY() + (height - ADJUST_BUTTON_SIZE) / 2;
            GuiRenderUtil.drawMCButton(
                graphics,
                buttonX,
                buttonY,
                ADJUST_BUTTON_SIZE,
                ADJUST_BUTTON_SIZE,
                adjustHovered,
                true
            );

            // Gear icon placeholder
            GuiRenderUtil.drawCenteredStringNoShadow(
                graphics,
                mc.font,
                "\u2699",
                buttonX + ADJUST_BUTTON_SIZE / 2,
                buttonY + (ADJUST_BUTTON_SIZE - mc.font.lineHeight) / 2 + 1,
                GuiRenderUtil.MC_TEXT_DARK
            );
        }

        // Remove button — MC-style with red tint
        if (showRemoveButton && hasItem) {
            int buttonX = getRemoveButtonX();
            int buttonY = getY() + (height - REMOVE_BUTTON_SIZE) / 2;
            GuiRenderUtil.drawMCButton(
                graphics,
                buttonX,
                buttonY,
                REMOVE_BUTTON_SIZE,
                REMOVE_BUTTON_SIZE,
                removeHovered,
                true
            );
            // Red-tinted overlay
            graphics.fill(
                buttonX + 1,
                buttonY + 1,
                buttonX + REMOVE_BUTTON_SIZE - 1,
                buttonY + REMOVE_BUTTON_SIZE - 1,
                removeHovered ? 0x40FF0000 : 0x20FF0000
            );

            // X icon
            GuiRenderUtil.drawCenteredStringNoShadow(
                graphics,
                mc.font,
                "X",
                buttonX + REMOVE_BUTTON_SIZE / 2,
                buttonY + (REMOVE_BUTTON_SIZE - mc.font.lineHeight) / 2 + 1,
                0xFFCC4444
            );
        }

        // Tooltip on hover
        if (hovered && hasItem && !anyButtonHovered) {
            renderTooltip(graphics, mouseX, mouseY, stack);
        }
    }

    /**
     * Get the slot label text from the region's translation key.
     */
    private String getSlotLabel() {
        return Component.translatable(
            "gui.tiedup.region." + region.name().toLowerCase()
        ).getString();
    }

    /**
     * Render item tooltip.
     */
    private void renderTooltip(
        GuiGraphics graphics,
        int mouseX,
        int mouseY,
        ItemStack stack
    ) {
        Minecraft mc = Minecraft.getInstance();
        List<Component> tooltip = new ArrayList<>();

        // Item name
        tooltip.add(stack.getHoverName());

        // Add region info
        tooltip.add(
            Component.translatable(
                "gui.tiedup.region." + region.name().toLowerCase()
            ).withStyle(ChatFormatting.GRAY)
        );

        graphics.renderTooltip(
            mc.font,
            tooltip,
            java.util.Optional.empty(),
            mouseX,
            mouseY
        );
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        if (isMouseOver(mouseX, mouseY) && button == 0) {
            // Check if equip button was clicked (empty slot only)
            if (isEquipButtonHovered(mouseX, mouseY)) {
                if (onEquipClick != null) {
                    onEquipClick.accept(this);
                    playDownSound(Minecraft.getInstance().getSoundManager());
                    return true;
                }
            }
            // Check if remove button was clicked
            else if (isRemoveButtonHovered(mouseX, mouseY)) {
                if (onRemoveClick != null) {
                    onRemoveClick.accept(this);
                    playDownSound(Minecraft.getInstance().getSoundManager());
                    return true;
                }
            }
            // Check if adjust button was clicked
            else if (isAdjustButtonHovered(mouseX, mouseY)) {
                if (onAdjustClick != null) {
                    onAdjustClick.accept(this);
                    playDownSound(Minecraft.getInstance().getSoundManager());
                    return true;
                }
            } else {
                // Main slot click
                if (onClick != null) {
                    onClick.accept(this);
                    playDownSound(Minecraft.getInstance().getSoundManager());
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected void updateWidgetNarration(NarrationElementOutput output) {
        ItemStack stack = itemGetter.get();
        Component narration;

        if (stack.isEmpty()) {
            narration = Component.translatable(
                "gui.tiedup.slot_empty",
                getSlotLabel()
            );
        } else {
            narration = Component.translatable(
                "gui.tiedup.slot_item",
                getSlotLabel(),
                stack.getHoverName()
            );
        }

        output.add(NarratedElementType.TITLE, narration);
    }
}
