package com.tiedup.remake.minigame;

import java.util.Random;
import java.util.UUID;

/**
 *
 * Tracks:
 * - Session UUID (anti-cheat)
 * - Sweet spot position and width
 * - Current lockpick position
 * - Remaining lockpick uses
 */
public class LockpickMiniGameState {

    private final UUID sessionId;
    private final UUID playerId;
    private final long createdAt;
    private final LockpickTargetKind targetKind;
    private final int targetData;

    /**
     * Session timeout in milliseconds (2 minutes)
     */
    private static final long SESSION_TIMEOUT_MS = 2L * 60L * 1000L;

    /**
     * Position of the sweet spot center (0.0 to 1.0)
     * BUG FIX: Removed final to allow regeneration after failed attempts.
     */
    private float sweetSpotCenter;

    /**
     * Width of the sweet spot (0.0 to 1.0, e.g. 0.15 = 15%)
     */
    private final float sweetSpotWidth;

    /**
     * Current lockpick position (0.0 to 1.0)
     */
    private float currentPosition;

    /**
     * Number of remaining lockpick uses
     */
    private int remainingUses;

    /**
     * Whether the session is complete
     */
    private boolean complete;

    /**
     * Whether the lock was successfully picked
     */
    private boolean success;

    private final Random random = new Random();

    public LockpickMiniGameState(
        UUID playerId,
        LockpickTargetKind targetKind,
        int targetData,
        float sweetSpotWidth
    ) {
        this.sessionId = UUID.randomUUID();
        this.playerId = playerId;
        this.targetKind = targetKind;
        this.targetData = targetData;
        this.createdAt = System.currentTimeMillis();

        // Generate random sweet spot position
        // Keep it away from edges (at least width/2 from 0 and 1)
        float minCenter = sweetSpotWidth / 2;
        float maxCenter = 1.0f - sweetSpotWidth / 2;
        this.sweetSpotCenter =
            minCenter + random.nextFloat() * (maxCenter - minCenter);
        this.sweetSpotWidth = sweetSpotWidth;

        // Start position at random location
        this.currentPosition = random.nextFloat();
        this.remainingUses = 5; // Default, will be updated by caller
        this.complete = false;
        this.success = false;
    }

    // ==================== GETTERS ====================

    public UUID getSessionId() {
        return sessionId;
    }

    public UUID getPlayerId() {
        return playerId;
    }

    public LockpickTargetKind getTargetKind() {
        return targetKind;
    }

    public int getTargetData() {
        return targetData;
    }

    public float getSweetSpotCenter() {
        return sweetSpotCenter;
    }

    public float getSweetSpotWidth() {
        return sweetSpotWidth;
    }

    public float getCurrentPosition() {
        return currentPosition;
    }

    public int getRemainingUses() {
        return remainingUses;
    }

    public boolean isComplete() {
        return complete;
    }

    public boolean isSuccess() {
        return success;
    }

    public boolean isExpired() {
        return System.currentTimeMillis() - createdAt > SESSION_TIMEOUT_MS;
    }

    // ==================== SETTERS ====================

    public void setRemainingUses(int uses) {
        this.remainingUses = uses;
    }

    public void setCurrentPosition(float position) {
        this.currentPosition = Math.max(0.0f, Math.min(1.0f, position));
    }

    // ==================== GAME LOGIC ====================

    /**
     * Move the lockpick position.
     *
     * @param delta Amount to move (-1.0 to 1.0, scaled by sensitivity)
     */
    public void move(float delta) {
        currentPosition = Math.max(
            0.0f,
            Math.min(1.0f, currentPosition + delta)
        );
    }

    /**
     * Check if current position is within the sweet spot.
     */
    public boolean isInSweetSpot() {
        float minPos = sweetSpotCenter - sweetSpotWidth / 2;
        float maxPos = sweetSpotCenter + sweetSpotWidth / 2;
        return currentPosition >= minPos && currentPosition <= maxPos;
    }

    /**
     * Attempt to pick the lock at current position.
     *
     * @return Result of the attempt
     */
    public PickAttemptResult attemptPick() {
        if (complete) {
            return PickAttemptResult.SESSION_COMPLETE;
        }

        if (isInSweetSpot()) {
            // Success!
            complete = true;
            success = true;
            return PickAttemptResult.SUCCESS;
        }

        // Failed - use up a lockpick
        remainingUses--;

        if (remainingUses <= 0) {
            // Out of lockpicks
            complete = true;
            return PickAttemptResult.OUT_OF_PICKS;
        }

        // Generate new sweet spot position for next attempt
        regenerateSweetSpot();

        return PickAttemptResult.MISSED;
    }

    /**
     * Regenerate sweet spot position (called after failed attempt).
     * BUG FIX: Actually regenerate the sweet spot to prevent players from memorizing position.
     * Problem: Players could memorize position and lockpicking became trivial.
     */
    private void regenerateSweetSpot() {
        // Generate new random sweet spot position
        // Keep it away from edges (at least width/2 from 0 and 1)
        float minCenter = sweetSpotWidth / 2;
        float maxCenter = 1.0f - sweetSpotWidth / 2;
        this.sweetSpotCenter =
            minCenter + random.nextFloat() * (maxCenter - minCenter);
    }

    /**
     * Get distance from current position to sweet spot center.
     * Used for feedback (closer = warmer).
     *
     * @return Distance as 0.0 (exact) to 1.0 (max distance)
     */
    public float getDistanceToSweetSpot() {
        return Math.abs(currentPosition - sweetSpotCenter);
    }

    /**
     * Get warmth feedback (how close to sweet spot).
     *
     * @return Warmth level: COLD, WARM, HOT, IN_SPOT
     */
    public WarmthLevel getWarmthLevel() {
        if (isInSweetSpot()) {
            return WarmthLevel.IN_SPOT;
        }

        float distance = getDistanceToSweetSpot();
        if (distance < sweetSpotWidth) {
            return WarmthLevel.HOT;
        } else if (distance < sweetSpotWidth * 2) {
            return WarmthLevel.WARM;
        }
        return WarmthLevel.COLD;
    }

    /**
     * Result of a pick attempt.
     */
    public enum PickAttemptResult {
        /**
         * Successfully picked the lock!
         */
        SUCCESS,

        /**
         * Missed the sweet spot, lockpick used
         */
        MISSED,

        /**
         * Ran out of lockpicks
         */
        OUT_OF_PICKS,

        /**
         * Session already complete
         */
        SESSION_COMPLETE,
    }

    /**
     * Warmth feedback level.
     */
    public enum WarmthLevel {
        COLD,
        WARM,
        HOT,
        IN_SPOT,
    }

    @Override
    public String toString() {
        return String.format(
            "LockpickMiniGameState{session=%s, player=%s, kind=%s, data=%d, pos=%.2f, sweet=%.2f(w=%.2f), uses=%d}",
            sessionId.toString().substring(0, 8),
            playerId.toString().substring(0, 8),
            targetKind,
            targetData,
            currentPosition,
            sweetSpotCenter,
            sweetSpotWidth,
            remainingUses
        );
    }
}
