using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using TMPro;
using DG.Tweening;

public class HurdleManager : MonoBehaviour
{
    public PlayerPathRunner playerRunner;
    public List<Transform> hurdles = new();
    public TMP_Text distanceToHurdleText;
    public TMP_Text tapsRequiredText;
    public DOTweenPath pathSource;

    private bool challengeRunning = false;
    private int currentTapCount = 0;
    public Transform currentHurdle = null;
    private int requiredTaps;
    private Coroutine activeChallenge;

    private Vector3[] drawPoints;
    private float gameStartTime;
    private bool challengeCompleted = false;
    private bool gameOver = false;

    void Start()
    {
        if (pathSource != null)
            drawPoints = pathSource.GetDrawPoints();
        
        gameStartTime = Time.time;
    }

    void Update()
    {
        // Stop everything if game is over
        if (gameOver) return;
        
        // Wait a bit before starting challenges to let speed stabilize
        if (Time.time - gameStartTime < 1f) return;
        
        if (!challengeRunning && hurdles.Count > 0)
        {
            StartNextChallenge();
        }
        else if (challengeRunning)
        {
            CountTaps();
            CheckForJump();
        }
    }

    void StartNextChallenge()
    {
        if (playerRunner == null || drawPoints == null || hurdles.Count == 0) return;

        currentHurdle = hurdles[0];
        requiredTaps = UnityEngine.Random.Range(2, 8);
        currentTapCount = 0;
        challengeCompleted = false;

        activeChallenge = StartCoroutine(StartTapChallenge());
        challengeRunning = true;
    }

    IEnumerator StartTapChallenge()
    {
        Debug.Log($"🟢 Challenge started! Tap {requiredTaps} times before reaching the hurdle!");

        while (currentHurdle != null && hurdles.Contains(currentHurdle))
        {
            // Calculate distance in real-time
            float remainingDistance = GetRemainingDistance(playerRunner.transform.position, currentHurdle.position);
            
            // Update UI with distance
            if (distanceToHurdleText != null)
                distanceToHurdleText.text = $"{remainingDistance:F1}m";

            if (tapsRequiredText != null)
            {
                if (challengeCompleted)
                    tapsRequiredText.text = "✓ Complete!";
                else
                {
                    tapsRequiredText.text ="Tap " +  (requiredTaps - currentTapCount) + " times!";
                    
                }
            }

            // Check if challenge is completed
            if (currentTapCount >= requiredTaps && !challengeCompleted)
            {
                Debug.Log("✅ Challenge Completed! Ready to jump!");
                challengeCompleted = true;
                // Don't remove hurdle or end challenge yet - wait for jump
            }

            yield return null;
        }
    }

    void CountTaps()
    {
        if (Input.GetMouseButtonDown(0) || (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began))
        {
            currentTapCount++;
            Debug.Log($"Tap {currentTapCount}/{requiredTaps}");
        }
    }

    void CheckForJump()
    {
        if (currentHurdle == null || playerRunner.IsJumping()) return;

        float remainingDistance = GetRemainingDistance(playerRunner.transform.position, currentHurdle.position);

        // When very close to hurdle and challenge is completed
        if (remainingDistance < 5f && challengeCompleted)
        {
            // Trigger jump in the PlayerPathRunner
            playerRunner.TriggerJump(() => {
                // This callback runs after jump completes
                if (currentHurdle != null)
                {
                    hurdles.Remove(currentHurdle);
                    if (activeChallenge != null)
                        StopCoroutine(activeChallenge);
                    EndChallengeUI();
                }
            });
        }
    }

    void EndChallengeUI()
    {
        challengeRunning = false;
        currentHurdle = null;
        if (distanceToHurdleText != null) distanceToHurdleText.text = "";
        if (tapsRequiredText != null) tapsRequiredText.text = "";
        activeChallenge = null;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Hurdle"))
        {
            // Check if this is the current hurdle and challenge wasn't completed
            if (other.transform == currentHurdle && !challengeCompleted && !playerRunner.IsJumping())
            {
                Debug.Log("❌ GAME OVER! Failed to complete tap challenge!");
                GameOver();
            }
        }
    }

    void GameOver()
    {
        gameOver = true;
        
        // Stop all coroutines
        if (activeChallenge != null)
            StopCoroutine(activeChallenge);
        
        // Clear UI
        EndChallengeUI();
        
        // Stop player movement
        playerRunner.enabled = false;
        
        // Show game over UI
        if (tapsRequiredText != null)
            tapsRequiredText.text = "GAME OVER!";
        
        Debug.Log("💀 GAME OVER - Player failed to clear hurdle!");
        
        // You can add more game over logic here:
        // - Show game over screen
        // - Play game over sound
        // - Show restart button
        // - Save score, etc.
    }

    float GetRemainingDistance(Vector3 playerPos, Vector3 hurdlePos)
    {
        if (drawPoints == null || drawPoints.Length < 2) return 0f;

        // Find closest point indices for player and hurdle
        int playerIndex = GetClosestPathSegmentIndex(playerPos);
        int hurdleIndex = GetClosestPathSegmentIndex(hurdlePos);

        // If player is past the hurdle, return 0
        if (playerIndex >= hurdleIndex) return 0f;

        float totalDistance = 0f;

        // Calculate distance from player to the end of its current segment
        Vector3 playerClosestPoint = GetClosestPointOnSegment(drawPoints[playerIndex], drawPoints[playerIndex + 1], playerPos);
        totalDistance += Vector3.Distance(playerClosestPoint, drawPoints[playerIndex + 1]);

        // Add distances of complete segments between player and hurdle
        for (int i = playerIndex + 1; i < hurdleIndex; i++)
        {
            totalDistance += Vector3.Distance(drawPoints[i], drawPoints[i + 1]);
        }

        // Add distance from start of hurdle's segment to hurdle position
        if (playerIndex < hurdleIndex)
        {
            Vector3 hurdleClosestPoint = GetClosestPointOnSegment(drawPoints[hurdleIndex], drawPoints[hurdleIndex + 1], hurdlePos);
            totalDistance += Vector3.Distance(drawPoints[hurdleIndex], hurdleClosestPoint);
        }

        return totalDistance;
    }

    int GetClosestPathSegmentIndex(Vector3 worldPos)
    {
        float minDist = float.MaxValue;
        int closestIndex = 0;

        for (int i = 0; i < drawPoints.Length - 1; i++)
        {
            Vector3 closestPoint = GetClosestPointOnSegment(drawPoints[i], drawPoints[i + 1], worldPos);
            float dist = Vector3.Distance(worldPos, closestPoint);

            if (dist < minDist)
            {
                minDist = dist;
                closestIndex = i;
            }
        }

        return closestIndex;
    }

    Vector3 GetClosestPointOnSegment(Vector3 a, Vector3 b, Vector3 point)
    {
        Vector3 ab = b - a;
        float t = Mathf.Clamp01(Vector3.Dot(point - a, ab) / Vector3.Dot(ab, ab));
        return a + t * ab;
    }
}