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

import com.tiedup.remake.client.gui.util.GuiRenderUtil;
import com.tiedup.remake.items.GenericKnife;
import com.tiedup.remake.items.ItemKey;
import com.tiedup.remake.items.ItemLockpick;
import com.tiedup.remake.items.ModItems;
import com.tiedup.remake.items.base.IHasResistance;
import com.tiedup.remake.items.base.ILockable;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.network.ModNetwork;
import com.tiedup.remake.network.action.PacketSetKnifeCutTarget;
import com.tiedup.remake.network.minigame.PacketLockpickMiniGameStart;
import com.tiedup.remake.network.slave.PacketMasterEquip;
import com.tiedup.remake.network.slave.PacketSlaveItemManage;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import com.tiedup.remake.v2.bondage.network.PacketV2SelfEquip;
import com.tiedup.remake.v2.bondage.network.PacketV2SelfLock;
import com.tiedup.remake.v2.bondage.network.PacketV2SelfRemove;
import com.tiedup.remake.v2.bondage.network.PacketV2SelfUnlock;
import com.tiedup.remake.v2.bondage.network.PacketV2StruggleStart;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
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.world.entity.LivingEntity;
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;

/**
 * Contextual action panel for the unified bondage screen.
 * Shows different actions based on mode (SELF/MASTER) and selected item state.
 */
@OnlyIn(Dist.CLIENT)
public class ActionPanel extends AbstractWidget {

    public enum ScreenMode {
        SELF,
        MASTER,
    }

    private record ActionEntry(
        String labelKey,
        boolean enabled,
        String disabledReasonKey,
        Runnable onClick
    ) {}

    // Layout
    private static final int BUTTON_WIDTH = 80;
    private static final int BUTTON_HEIGHT = 22;
    private static final int BUTTON_SPACING = 6;
    private static final int COLUMNS = 3;
    private static final int PADDING = 8;

    // Colors (vanilla MC style)
    private static final int TEXT_ENABLED = 0xFF404040;
    private static final int TEXT_DISABLED = 0xFF909090;
    private static final int TITLE_COLOR = 0xFF404040;

    private ScreenMode mode = ScreenMode.SELF;
    private BodyRegionV2 selectedRegion;
    private ItemStack selectedItem = ItemStack.EMPTY;
    private LivingEntity targetEntity;
    private UUID targetEntityUUID;
    private UUID keyUUID;
    private boolean isMasterKey;
    private final List<ActionEntry> actions = new ArrayList<>();

    // Callbacks for actions that open other screens
    private Consumer<BodyRegionV2> onAdjustRequested;
    private Consumer<BodyRegionV2> onEquipRequested;
    private Runnable onCellAssignRequested;
    private Runnable onCloseRequested;

    // Hovered button index for tooltip
    private int hoveredIndex = -1;

    public ActionPanel(int x, int y, int width, int height) {
        super(x, y, width, height, Component.translatable("gui.tiedup.action_panel"));
    }

    public void setMode(ScreenMode mode) {
        this.mode = mode;
    }

    public void setTargetEntity(LivingEntity entity) {
        this.targetEntity = entity;
        this.targetEntityUUID = entity != null ? entity.getUUID() : null;
    }

    public void setKeyInfo(UUID keyUUID, boolean isMasterKey) {
        this.keyUUID = keyUUID;
        this.isMasterKey = isMasterKey;
    }

    public void setOnAdjustRequested(Consumer<BodyRegionV2> cb) {
        this.onAdjustRequested = cb;
    }

    public void setOnEquipRequested(Consumer<BodyRegionV2> cb) {
        this.onEquipRequested = cb;
    }

    public void setOnCellAssignRequested(Runnable cb) {
        this.onCellAssignRequested = cb;
    }

    public void setOnCloseRequested(Runnable cb) {
        this.onCloseRequested = cb;
    }

    /**
     * Update the action panel context. Call when the selected slot changes.
     */
    public void setContext(BodyRegionV2 region, ItemStack item) {
        this.selectedRegion = region;
        this.selectedItem = item != null ? item : ItemStack.EMPTY;
        rebuildActions();
    }

    /** Clear the selection — no slot selected. */
    public void clearContext() {
        this.selectedRegion = null;
        this.selectedItem = ItemStack.EMPTY;
        actions.clear();
    }

    private void rebuildActions() {
        actions.clear();
        if (selectedRegion == null) return;

        Player localPlayer = Minecraft.getInstance().player;
        if (localPlayer == null) return;

        if (mode == ScreenMode.SELF) {
            buildSelfActions(localPlayer);
        } else {
            buildMasterActions(localPlayer);
        }
    }

    /**
     * Find a key item in the player's inventory.
     * ItemKey.findKeyInInventory does not exist, so we implement it inline.
     */
    private static ItemStack findKeyInInventory(Player player) {
        ItemStack masterKeyStack = ItemStack.EMPTY;
        for (int i = 0; i < player.getInventory().getContainerSize(); i++) {
            ItemStack stack = player.getInventory().getItem(i);
            if (stack.isEmpty()) continue;
            if (stack.getItem() instanceof ItemKey) {
                return stack; // Regular key takes priority
            }
            if (
                masterKeyStack.isEmpty() && stack.is(ModItems.MASTER_KEY.get())
            ) {
                masterKeyStack = stack; // Remember master key as fallback
            }
        }
        return masterKeyStack; // Empty or master key
    }

    private void buildSelfActions(Player player) {
        boolean isEmpty = selectedItem.isEmpty();
        boolean armsOccupied = V2EquipmentHelper.isRegionOccupied(
            player,
            BodyRegionV2.ARMS
        );
        boolean handsOccupied = V2EquipmentHelper.isRegionOccupied(
            player,
            BodyRegionV2.HANDS
        );
        boolean armsFree = !armsOccupied;
        boolean handsFree = !handsOccupied;

        boolean isLocked = false;
        boolean isLockable = false;
        boolean isJammed = false;
        boolean hasMittens = V2EquipmentHelper.isRegionOccupied(
            player,
            BodyRegionV2.HANDS
        );
        if (!isEmpty && selectedItem.getItem() instanceof ILockable lockable) {
            isLocked = lockable.isLocked(selectedItem);
            isLockable = lockable.isLockable(selectedItem);
            isJammed = lockable.isJammed(selectedItem);
        }

        boolean hasLockpick = !ItemLockpick.findLockpickInInventory(
            player
        ).isEmpty();
        boolean hasKnife = !GenericKnife.findKnifeInInventory(player).isEmpty();
        ItemStack foundKey = findKeyInInventory(player);
        boolean hasKey = !foundKey.isEmpty();
        boolean foundKeyIsMaster =
            hasKey && foundKey.is(ModItems.MASTER_KEY.get());

        if (isEmpty) {
            // Equip action for empty slot
            actions.add(
                new ActionEntry("gui.tiedup.action.equip", true, null, () -> {
                    if (onEquipRequested != null) onEquipRequested.accept(
                        selectedRegion
                    );
                })
            );
            return;
        }

        // Remove
        boolean canRemove =
            armsFree &&
            handsFree &&
            !isLocked &&
            selectedRegion != BodyRegionV2.ARMS;
        String removeReason = isLocked
            ? "gui.tiedup.reason.locked"
            : !armsFree
                ? "gui.tiedup.reason.arms_bound"
                : !handsFree
                    ? "gui.tiedup.reason.hands_bound"
                    : selectedRegion == BodyRegionV2.ARMS
                        ? "gui.tiedup.reason.use_struggle"
                        : null;
        actions.add(
            new ActionEntry(
                "gui.tiedup.action.remove",
                canRemove,
                removeReason,
                () ->
                    ModNetwork.sendToServer(
                        new PacketV2SelfRemove(selectedRegion)
                    )
            )
        );

        // Struggle (locked items only)
        if (isLocked) {
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.struggle",
                    true,
                    null,
                    () -> {
                        ModNetwork.sendToServer(
                            new PacketV2StruggleStart(selectedRegion)
                        );
                        if (onCloseRequested != null) onCloseRequested.run();
                    }
                )
            );
        }

        // Lockpick
        if (isLocked) {
            boolean canPick = hasLockpick && !hasMittens && !isJammed;
            String pickReason = !hasLockpick
                ? "gui.tiedup.reason.no_lockpick"
                : hasMittens
                    ? "gui.tiedup.reason.mittens"
                    : isJammed
                        ? "gui.tiedup.reason.jammed"
                        : null;
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.lockpick",
                    canPick,
                    pickReason,
                    () -> {
                        ModNetwork.sendToServer(
                            new PacketLockpickMiniGameStart(selectedRegion)
                        );
                        if (onCloseRequested != null) onCloseRequested.run();
                    }
                )
            );
        }

        // Cut
        if (isLocked) {
            boolean canCut = hasKnife && !hasMittens;
            String cutReason = !hasKnife
                ? "gui.tiedup.reason.no_knife"
                : hasMittens
                    ? "gui.tiedup.reason.mittens"
                    : null;
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.cut",
                    canCut,
                    cutReason,
                    () -> {
                        ModNetwork.sendToServer(
                            new PacketSetKnifeCutTarget(selectedRegion)
                        );
                        if (onCloseRequested != null) onCloseRequested.run();
                    }
                )
            );
        }

        // Adjust (MOUTH, EYES only)
        if (
            selectedRegion == BodyRegionV2.MOUTH ||
            selectedRegion == BodyRegionV2.EYES
        ) {
            actions.add(
                new ActionEntry("gui.tiedup.action.adjust", true, null, () -> {
                    if (onAdjustRequested != null) onAdjustRequested.accept(
                        selectedRegion
                    );
                })
            );
        }

        // Lock (self, with key, arms free)
        if (isLockable && !isLocked) {
            boolean canLock = hasKey && armsFree;
            String lockReason = !hasKey
                ? "gui.tiedup.reason.no_key"
                : !armsFree
                    ? "gui.tiedup.reason.arms_bound"
                    : null;
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.lock",
                    canLock,
                    lockReason,
                    () ->
                        ModNetwork.sendToServer(
                            new PacketV2SelfLock(selectedRegion)
                        )
                )
            );
        }

        // Unlock (self, with matching key, arms free)
        if (isLocked) {
            boolean keyMatches = false;
            if (
                hasKey && selectedItem.getItem() instanceof ILockable lockable
            ) {
                if (foundKeyIsMaster) {
                    keyMatches = true; // Master key matches all locks
                } else if (foundKey.getItem() instanceof ItemKey itemKey) {
                    UUID lockKeyUUID = lockable.getLockedByKeyUUID(
                        selectedItem
                    );
                    UUID foundKeyUUID = itemKey.getKeyUUID(foundKey);
                    keyMatches =
                        lockKeyUUID == null || lockKeyUUID.equals(foundKeyUUID);
                }
            }
            boolean canUnlock = hasKey && armsFree && keyMatches;
            String unlockReason = !hasKey
                ? "gui.tiedup.reason.no_key"
                : !armsFree
                    ? "gui.tiedup.reason.arms_bound"
                    : !keyMatches
                        ? "gui.tiedup.reason.wrong_key"
                        : null;
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.unlock",
                    canUnlock,
                    unlockReason,
                    () ->
                        ModNetwork.sendToServer(
                            new PacketV2SelfUnlock(selectedRegion)
                        )
                )
            );
        }
    }

    private void buildMasterActions(Player master) {
        boolean isEmpty = selectedItem.isEmpty();

        boolean isLocked = false;
        boolean isLockable = false;
        if (!isEmpty && selectedItem.getItem() instanceof ILockable lockable) {
            isLocked = lockable.isLocked(selectedItem);
            isLockable = lockable.isLockable(selectedItem);
        }

        if (isEmpty) {
            actions.add(
                new ActionEntry("gui.tiedup.action.equip", true, null, () -> {
                    if (onEquipRequested != null) onEquipRequested.accept(
                        selectedRegion
                    );
                })
            );
            return;
        }

        // Remove
        actions.add(
            new ActionEntry(
                "gui.tiedup.action.remove",
                !isLocked,
                isLocked ? "gui.tiedup.reason.locked" : null,
                () ->
                    ModNetwork.sendToServer(
                        new PacketSlaveItemManage(
                            targetEntityUUID,
                            selectedRegion,
                            PacketSlaveItemManage.Action.REMOVE,
                            keyUUID,
                            isMasterKey
                        )
                    )
            )
        );

        // Lock
        if (isLockable && !isLocked) {
            actions.add(
                new ActionEntry("gui.tiedup.action.lock", true, null, () ->
                    ModNetwork.sendToServer(
                        new PacketSlaveItemManage(
                            targetEntityUUID,
                            selectedRegion,
                            PacketSlaveItemManage.Action.LOCK,
                            keyUUID,
                            isMasterKey
                        )
                    )
                )
            );
        }

        // Unlock
        if (isLocked) {
            actions.add(
                new ActionEntry("gui.tiedup.action.unlock", true, null, () ->
                    ModNetwork.sendToServer(
                        new PacketSlaveItemManage(
                            targetEntityUUID,
                            selectedRegion,
                            PacketSlaveItemManage.Action.UNLOCK,
                            keyUUID,
                            isMasterKey
                        )
                    )
                )
            );
        }

        // Adjust (MOUTH, EYES)
        if (
            selectedRegion == BodyRegionV2.MOUTH ||
            selectedRegion == BodyRegionV2.EYES
        ) {
            actions.add(
                new ActionEntry("gui.tiedup.action.adjust", true, null, () -> {
                    if (onAdjustRequested != null) onAdjustRequested.accept(
                        selectedRegion
                    );
                })
            );
        }

        // Bondage Service toggle (NECK collar only, prison configured)
        if (
            selectedRegion == BodyRegionV2.NECK &&
            CollarHelper.isCollar(selectedItem)
        ) {
            if (CollarHelper.hasCellAssigned(selectedItem)) {
                boolean svcEnabled = CollarHelper.isBondageServiceEnabled(
                    selectedItem
                );
                String svcKey = svcEnabled
                    ? "gui.tiedup.action.svc_off"
                    : "gui.tiedup.action.svc_on";
                actions.add(
                    new ActionEntry(svcKey, true, null, () ->
                        ModNetwork.sendToServer(
                            new PacketSlaveItemManage(
                                targetEntityUUID,
                                selectedRegion,
                                PacketSlaveItemManage.Action.TOGGLE_BONDAGE_SERVICE,
                                keyUUID,
                                isMasterKey
                            )
                        )
                    )
                );
            }
            // Cell assign
            actions.add(
                new ActionEntry(
                    "gui.tiedup.action.cell_assign",
                    true,
                    null,
                    () -> {
                        if (
                            onCellAssignRequested != null
                        ) onCellAssignRequested.run();
                    }
                )
            );
        }
    }

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

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

        // Title
        String title;
        if (selectedRegion == null) {
            title = Component.translatable(
                "gui.tiedup.action.no_selection"
            ).getString();
        } else if (selectedItem.isEmpty()) {
            title = Component.translatable(
                "gui.tiedup.action.title_empty",
                Component.translatable(
                    "gui.tiedup.region." + selectedRegion.name().toLowerCase()
                )
            ).getString();
        } else {
            title =
                (mode == ScreenMode.MASTER ? "\u265B " : "") +
                selectedItem.getHoverName().getString();
        }
        graphics.drawString(
            mc.font,
            title,
            getX() + PADDING,
            getY() + PADDING,
            TITLE_COLOR,
            false
        );

        // Action buttons grid (MC-style buttons)
        hoveredIndex = -1;
        int startY = getY() + PADDING + mc.font.lineHeight + 6;
        int startX = getX() + PADDING;

        for (int i = 0; i < actions.size(); i++) {
            ActionEntry action = actions.get(i);
            int col = i % COLUMNS;
            int row = i / COLUMNS;
            int btnX = startX + col * (BUTTON_WIDTH + BUTTON_SPACING);
            int btnY = startY + row * (BUTTON_HEIGHT + 4);

            boolean hovered =
                mouseX >= btnX &&
                mouseX < btnX + BUTTON_WIDTH &&
                mouseY >= btnY &&
                mouseY < btnY + BUTTON_HEIGHT;
            if (hovered) hoveredIndex = i;

            int textColor = action.enabled() ? TEXT_ENABLED : TEXT_DISABLED;
            GuiRenderUtil.drawMCButton(
                graphics,
                btnX,
                btnY,
                BUTTON_WIDTH,
                BUTTON_HEIGHT,
                hovered,
                action.enabled()
            );

            String label = Component.translatable(
                action.labelKey()
            ).getString();
            int textX = btnX + (BUTTON_WIDTH - mc.font.width(label)) / 2;
            int textY = btnY + (BUTTON_HEIGHT - mc.font.lineHeight) / 2;
            graphics.drawString(mc.font, label, textX, textY, textColor, false);
        }

        // Tooltip for disabled button
        if (hoveredIndex >= 0 && hoveredIndex < actions.size()) {
            ActionEntry hoverAction = actions.get(hoveredIndex);
            if (
                !hoverAction.enabled() &&
                hoverAction.disabledReasonKey() != null
            ) {
                graphics.renderTooltip(
                    mc.font,
                    Component.translatable(hoverAction.disabledReasonKey()),
                    mouseX,
                    mouseY
                );
            }
        }
    }

    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        if (!isMouseOver(mouseX, mouseY) || button != 0) return false;

        Minecraft mc = Minecraft.getInstance();
        int startY = getY() + PADDING + mc.font.lineHeight + 6;
        int startX = getX() + PADDING;

        for (int i = 0; i < actions.size(); i++) {
            ActionEntry action = actions.get(i);
            int col = i % COLUMNS;
            int row = i / COLUMNS;
            int btnX = startX + col * (BUTTON_WIDTH + BUTTON_SPACING);
            int btnY = startY + row * (BUTTON_HEIGHT + 4);

            if (
                mouseX >= btnX &&
                mouseX < btnX + BUTTON_WIDTH &&
                mouseY >= btnY &&
                mouseY < btnY + BUTTON_HEIGHT
            ) {
                if (action.enabled() && action.onClick() != null) {
                    action.onClick().run();
                    playDownSound(mc.getSoundManager());
                    return true;
                }
                return false; // Clicked disabled button
            }
        }
        return false;
    }

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