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

import com.tiedup.remake.client.gui.util.GuiColors;
import com.tiedup.remake.client.gui.util.GuiLayoutConstants;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.network.ModNetwork;
import com.tiedup.remake.network.minigame.PacketLockpickAttempt;
import com.tiedup.remake.network.minigame.PacketLockpickMiniGameMove;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.lwjgl.glfw.GLFW;

/**
 *
 * Features:
 * - Sweet spot is HIDDEN (uniform gray bar)
 * - NO feedback during movement (A/D)
 * - Feedback ONLY when testing (SPACE): tension bar animation
 * - Tension bar fills up based on proximity, then bounces back if miss
 * - Success = tension bar fills to 100% and stays
 *
 * Visual layout:
 * ┌─────────────────────────────────────────┐
 * │           LOCKPICKING                   │
 * │                                         │
 * │  Position:                              │
 * │  ┌─────────────────────────────────┐   │
 * │  │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│   │  ← Uniform gray (sweet spot hidden)
 * │  └─────────────────────────────────┘   │
 * │              ▲                          │
 * │                                         │
 * │  Tension:                               │
 * │  ┌─────────────────────────────────┐   │
 * │  │████████████░░░░░░░░░░░░░░░░░░░░░│   │  ← Animates on test
 * │  └─────────────────────────────────┘   │
 * │                                         │
 * │  [A/D] Move  |  [SPACE] Test  |  ◉◉◉◎◎ │
 * └─────────────────────────────────────────┘
 */
@OnlyIn(Dist.CLIENT)
public class LockpickMiniGameScreen extends BaseScreen {

    private UUID sessionId;
    private float sweetSpotCenter;
    private float sweetSpotWidth;
    private float currentPosition;
    private int remainingUses;
    private int maxUses;

    // Visual state
    private boolean gameComplete;
    private boolean gameSuccess;
    private int completionDelayTicks;

    // Animation
    private float animatedPosition;

    // Movement
    private static final float MOVE_SPEED = 0.015f;
    private boolean movingLeft;
    private boolean movingRight;

    // Sync throttle
    private long lastSyncTime;
    private static final long SYNC_INTERVAL_MS = 50; // 20 updates per second max

    // ==================== TENSION BAR ANIMATION ====================

    /** Whether a tension animation is currently playing */
    private boolean isTesting = false;

    /** Target fill level for tension bar (0.0-1.0) */
    private float tensionFillTarget = 0f;

    /** Current fill level of tension bar (0.0-1.0) */
    private float tensionCurrent = 0f;

    /** Is the tension bar rising or falling (bouncing) */
    private boolean tensionRising = true;

    /** Speed of tension bar fill */
    private static final float FILL_SPEED = 0.025f;

    /** Speed of tension bar bounce-back (slower than fill) */
    private static final float BOUNCE_SPEED = 0.015f;

    /** Color for tension bar based on fill target */
    private int tensionColor = 0xFFAA0000; // Red by default

    public LockpickMiniGameScreen(
        UUID sessionId,
        float sweetSpotCenter,
        float sweetSpotWidth,
        float currentPosition,
        int remainingUses
    ) {
        super(Component.translatable("gui.tiedup.lockpick_minigame"));
        this.sessionId = sessionId;
        this.sweetSpotCenter = sweetSpotCenter;
        this.sweetSpotWidth = sweetSpotWidth;
        this.currentPosition = currentPosition;
        this.animatedPosition = currentPosition;
        this.remainingUses = remainingUses;
        this.maxUses = remainingUses;

        this.gameComplete = false;
        this.gameSuccess = false;
    }

    @Override
    protected int getPreferredWidth() {
        return GuiLayoutConstants.getResponsiveWidth(
            this.width,
            0.5f,
            300,
            380
        );
    }

    @Override
    protected int getPreferredHeight() {
        return GuiLayoutConstants.getResponsiveHeight(
            this.height,
            0.45f,
            200,
            260
        );
    }

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

    @Override
    public void tick() {
        super.tick();

        // Handle continuous movement
        if (!gameComplete && !isTesting) {
            if (movingLeft && !movingRight) {
                movePosition(-MOVE_SPEED);
            } else if (movingRight && !movingLeft) {
                movePosition(MOVE_SPEED);
            }
        }

        // Animate position indicator
        animatedPosition = lerp(animatedPosition, currentPosition, 0.3f);

        // Animate tension bar
        if (isTesting) {
            if (tensionRising) {
                tensionCurrent += FILL_SPEED;
                if (tensionCurrent >= tensionFillTarget) {
                    tensionCurrent = tensionFillTarget;
                    if (tensionFillTarget < 1.0f) {
                        // Not success - start bouncing back
                        tensionRising = false;
                    }
                    // If 100%, keep it (success animation handled separately)
                }
            } else {
                // Bouncing back
                tensionCurrent -= BOUNCE_SPEED;
                if (tensionCurrent <= 0) {
                    tensionCurrent = 0;
                    isTesting = false; // Animation complete
                }
            }
        }

        // Completion delay
        if (gameComplete && completionDelayTicks > 0) {
            completionDelayTicks--;
            if (completionDelayTicks <= 0) {
                this.onClose();
            }
        }
    }

    private void movePosition(float delta) {
        float newPos = Math.max(0.0f, Math.min(1.0f, currentPosition + delta));
        if (newPos != currentPosition) {
            currentPosition = newPos;
            syncPositionToServer();
        }
    }

    private void syncPositionToServer() {
        long now = System.currentTimeMillis();
        if (now - lastSyncTime >= SYNC_INTERVAL_MS) {
            ModNetwork.sendToServer(
                new PacketLockpickMiniGameMove(sessionId, currentPosition)
            );
            lastSyncTime = now;
        }
    }

    /**
     * Called when the lock was successfully picked.
     * Triggers success animation (tension bar fills to 100% and stays).
     */
    public void onSuccess() {
        this.gameComplete = true;
        this.gameSuccess = true;
        this.completionDelayTicks = 60; // Wait for animation

        // Success animation: fill to 100%
        triggerSuccessAnimation();
    }

    /**
     * Called when the player missed the sweet spot.
     * Triggers tension bar animation based on distance.
     */
    public void onMissed(int newRemainingUses, float distance) {
        this.remainingUses = newRemainingUses;

        // Trigger tension animation based on distance
        triggerTensionAnimation(distance);
    }

    /**
     * Called when the player ran out of lockpicks.
     */
    public void onOutOfPicks() {
        this.gameComplete = true;
        this.gameSuccess = false;
        this.remainingUses = 0;
        this.completionDelayTicks = 40;

        // Final failed animation
        tensionFillTarget = 0.1f;
        tensionCurrent = 0f;
        tensionRising = true;
        tensionColor = 0xFFAA0000; // Red
        isTesting = true;
    }

    /**
     * Called when the session was cancelled.
     */
    public void onCancelled() {
        this.onClose();
    }

    /**
     * Trigger tension bar animation for a MISS based on distance.
     * Closer = fills more (but still bounces back).
     */
    private void triggerTensionAnimation(float distance) {
        isTesting = true;
        tensionRising = true;
        tensionCurrent = 0f;

        // Calculate fill target based on distance (sweet spot = 3% = 0.015 radius)
        if (distance < 0.05f) {
            tensionFillTarget = 0.85f; // Very close - fills a lot
            tensionColor = 0xFF00AA00; // Green
        } else if (distance < 0.10f) {
            tensionFillTarget = 0.60f; // Close
            tensionColor = 0xFFAAAA00; // Yellow
        } else if (distance < 0.20f) {
            tensionFillTarget = 0.35f; // Medium
            tensionColor = 0xFFFF8800; // Orange
        } else {
            tensionFillTarget = 0.15f; // Far - fills little
            tensionColor = 0xFFAA0000; // Red
        }

        TiedUpMod.LOGGER.debug(
            "[LockpickMiniGameScreen] Tension animation: distance={}, fillTarget={}",
            distance,
            tensionFillTarget
        );
    }

    /**
     * Trigger success animation - fills to 100% and stays.
     */
    private void triggerSuccessAnimation() {
        isTesting = true;
        tensionRising = true;
        tensionCurrent = 0f;
        tensionFillTarget = 1.0f; // Full!
        tensionColor = 0xFF00FF00; // Bright green
    }

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

        int centerX = this.width / 2;
        int y = this.topPos + GuiLayoutConstants.TITLE_HEIGHT + 15;

        // Position bar (uniform - sweet spot hidden)
        Component posLabel = Component.translatable(
            "gui.tiedup.lockpick_minigame.label.position"
        ).withStyle(ChatFormatting.GRAY);
        graphics.drawString(this.font, posLabel, centerX - 120, y, 0xFFFFFFFF);
        y += 12;
        renderPositionBar(graphics, y);
        y += 55;

        // Tension bar
        Component tensionLabel = Component.translatable(
            "gui.tiedup.lockpick_minigame.label.tension"
        ).withStyle(ChatFormatting.GRAY);
        graphics.drawString(
            this.font,
            tensionLabel,
            centerX - 120,
            y,
            0xFFFFFFFF
        );
        y += 12;
        renderTensionBar(graphics, y);
        y += 35;

        // Uses indicator
        renderUsesIndicator(graphics, y);
        y += 25;

        // Instructions or result
        if (gameComplete) {
            Component result = gameSuccess
                ? Component.translatable(
                      "gui.tiedup.lockpick_minigame.status.unlocked"
                  ).withStyle(ChatFormatting.GREEN, ChatFormatting.BOLD)
                : Component.translatable(
                      "gui.tiedup.lockpick_minigame.status.out_of_picks"
                  ).withStyle(ChatFormatting.RED, ChatFormatting.BOLD);
            int resultWidth = this.font.width(result);
            graphics.drawString(
                this.font,
                result,
                centerX - resultWidth / 2,
                y,
                0xFFFFFFFF
            );
        } else {
            Component hint = Component.translatable(
                "gui.tiedup.lockpick_minigame.hint"
            ).withStyle(ChatFormatting.GRAY);
            int hintWidth = this.font.width(hint);
            graphics.drawString(
                this.font,
                hint,
                centerX - hintWidth / 2,
                y,
                0xFFFFFFFF
            );
        }
    }

    /**
     * Render the position bar (uniform gray - sweet spot hidden).
     */
    private void renderPositionBar(GuiGraphics graphics, int y) {
        int barWidth = 240;
        int barHeight = 30;
        int barX = (this.width - barWidth) / 2;

        // Background - uniform dark gray (sweet spot is INVISIBLE)
        graphics.fill(barX, y, barX + barWidth, y + barHeight, 0xFF333333);

        // Border
        graphics.renderOutline(barX, y, barWidth, barHeight, 0xFF666666);

        // Lockpick indicator (position marker)
        int pickX = barX + (int) (animatedPosition * barWidth);
        int pickColor = 0xFFFFFF00; // Yellow

        // Draw lockpick as a triangle pointing down
        int pickWidth = 10;
        int pickHeight = 14;
        graphics.fill(
            pickX - pickWidth / 2,
            y - pickHeight,
            pickX + pickWidth / 2,
            y - 2,
            pickColor
        );
        graphics.fill(pickX - 1, y - 2, pickX + 1, y + 4, pickColor);

        // Draw pick position line
        graphics.fill(pickX - 1, y, pickX + 1, y + barHeight, 0xAAFFFFFF);
    }

    /**
     * Render the tension bar (animates during test).
     */
    private void renderTensionBar(GuiGraphics graphics, int y) {
        int barWidth = 240;
        int barHeight = 20;
        int barX = (this.width - barWidth) / 2;

        // Background
        graphics.fill(barX, y, barX + barWidth, y + barHeight, 0xFF222222);

        // Fill based on current tension
        if (tensionCurrent > 0) {
            int fillWidth = (int) (barWidth * tensionCurrent);
            graphics.fill(
                barX,
                y,
                barX + fillWidth,
                y + barHeight,
                tensionColor
            );
        }

        // Border
        graphics.renderOutline(barX, y, barWidth, barHeight, 0xFF555555);

        // Target line (100% marker)
        int targetX = barX + barWidth - 2;
        graphics.fill(targetX, y, targetX + 2, y + barHeight, 0xFFFFFFFF);
    }

    private void renderUsesIndicator(GuiGraphics graphics, int y) {
        int centerX = this.width / 2;

        // Draw use pips centered
        int totalPipWidth = maxUses * 14;
        int pipX = centerX - totalPipWidth / 2;

        for (int i = 0; i < maxUses; i++) {
            int pipColor = i < remainingUses ? 0xFF00AA00 : 0xFF333333;
            graphics.fill(
                pipX + i * 14,
                y,
                pipX + i * 14 + 10,
                y + 10,
                pipColor
            );
            graphics.renderOutline(pipX + i * 14, y, 10, 10, 0xFF666666);
        }
    }

    @Override
    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
        // ESC to cancel
        if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
            this.onClose();
            return true;
        }

        if (gameComplete || isTesting) {
            return super.keyPressed(keyCode, scanCode, modifiers);
        }

        // Movement keys
        if (keyCode == GLFW.GLFW_KEY_A || keyCode == GLFW.GLFW_KEY_LEFT) {
            movingLeft = true;
            return true;
        }
        if (keyCode == GLFW.GLFW_KEY_D || keyCode == GLFW.GLFW_KEY_RIGHT) {
            movingRight = true;
            return true;
        }

        // Test key
        if (keyCode == GLFW.GLFW_KEY_SPACE) {
            // Final sync before test
            ModNetwork.sendToServer(
                new PacketLockpickMiniGameMove(sessionId, currentPosition)
            );
            ModNetwork.sendToServer(new PacketLockpickAttempt(sessionId));
            return true;
        }

        return super.keyPressed(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
        if (keyCode == GLFW.GLFW_KEY_A || keyCode == GLFW.GLFW_KEY_LEFT) {
            movingLeft = false;
            return true;
        }
        if (keyCode == GLFW.GLFW_KEY_D || keyCode == GLFW.GLFW_KEY_RIGHT) {
            movingRight = false;
            return true;
        }
        return super.keyReleased(keyCode, scanCode, modifiers);
    }

    @Override
    public boolean isPauseScreen() {
        return false;
    }

    private float lerp(float current, float target, float speed) {
        if (Math.abs(current - target) < 0.001f) {
            return target;
        }
        return current + (target - current) * speed;
    }
}
