using System;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using DG.Tweening.Plugins.Core.PathCore;
using UnityEngine.SceneManagement;

public class PlayerPathRunner : MonoBehaviour
{
    [Header("Speed Settings")]
    public float baseSpeed = 2f;
    public float maxSpeed = 10f;
    public float acceleration = 5f;
    public float constantSpeed = 5f; // Speed to use when not in tap mode

    [Header("Tap Speed Mode")]
    public bool useTapToMove = true;
    public float tapWindowSeconds = 0.5f;

    [Header("Jump Settings")]
    public float jumpPower = 2f;
    public float jumpDuration = 0.5f;
    public float jumpDistance = 3f; // Distance in world units

    [Header("Path Setup")]
    public DOTweenPath pathSource;
    public bool faceMovementDirection = true;
    public float rotationSpeed = 10f;

    [Header("Hurdle Setup")]
    public List<Transform> hurdles; // Assign all hurdles here

    private List<float> tapTimestamps = new();
    private float currentSpeed = 0f;
    private float pathPosition = 0f;
    private Vector3[] drawPoints;
    private Path bakedPath;
    private bool isJumping = false;
    private System.Action onJumpComplete;

    private void Awake()
    {
        Application.targetFrameRate = 120;
    }

    void Start()
    {
        if (pathSource == null)
        {
            Debug.LogError("Path Source not assigned!");
            return;
        }

        // Bake DOTween path (we pause immediately)
        transform.DOPath(pathSource.wps.ToArray(), 1f, pathSource.pathType, pathSource.pathMode)
            .SetOptions(pathSource.isClosedPath)
            .SetEase(Ease.Linear)
            .SetLookAt(0)
            .Pause();

        drawPoints = pathSource.GetDrawPoints();

        if (drawPoints == null || drawPoints.Length < 2)
        {
            Debug.LogError("Draw points not generated properly.");
        }

        // Initialize speed based on mode
        if (!useTapToMove)
        {
            currentSpeed = constantSpeed;
        }
    }

    void Update()
    {
        // Don't process normal movement if jumping
        if (isJumping) return;

        if (useTapToMove)
        {
            HandleInput();
            UpdateSpeed();
        }
        else
        {
            // In constant mode, set speed directly without acceleration
            currentSpeed = constantSpeed;
        }

        MoveOnPath();
    }

    void HandleInput()
    {
        if (Input.GetMouseButtonDown(0) || Input.touchCount > 0)
        {
            tapTimestamps.Add(Time.time);
        }
    }

    void UpdateSpeed()
    {
        float cutoff = Time.time - tapWindowSeconds;
        tapTimestamps.RemoveAll(t => t < cutoff);

        float tps = tapTimestamps.Count / tapWindowSeconds;
        float targetSpeed = Mathf.Clamp(baseSpeed + tps, baseSpeed, maxSpeed);
        currentSpeed = Mathf.MoveTowards(currentSpeed, targetSpeed, acceleration * Time.deltaTime);
    }

    void MoveOnPath()
    {
        if (drawPoints == null || drawPoints.Length < 2) return;

        float speed = currentSpeed / 50f;
        pathPosition += speed * Time.deltaTime;
        pathPosition %= 1f;

        UpdatePositionOnPath(pathPosition);
    }

    void UpdatePositionOnPath(float normalizedPosition)
    {
        float floatIndex = normalizedPosition * (drawPoints.Length - 1);
        int iA = Mathf.FloorToInt(floatIndex);
        int iB = Mathf.Min(iA + 1, drawPoints.Length - 1);
        float t = floatIndex - iA;

        Vector3 pos = Vector3.Lerp(drawPoints[iA], drawPoints[iB], t);
        transform.position = pos;

        // Handle rotation to face movement direction
        if (faceMovementDirection && iB < drawPoints.Length)
        {
            Vector3 direction = drawPoints[iB] - drawPoints[iA];
            direction.y = 0; // Keep rotation only on Y axis (no tilting)
            
            if (direction != Vector3.zero)
            {
                Quaternion targetRotation = Quaternion.LookRotation(direction);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
            }
        }
    }

    public void TriggerJump(System.Action onComplete = null)
    {
        if (isJumping) return;

        Debug.Log("🦘 Jump triggered in PlayerPathRunner!");
        isJumping = true;
        onJumpComplete = onComplete;

        // Calculate how much to advance on the path based on world distance
        float pathLength = CalculateTotalPathLength();
        float jumpPercentage = jumpDistance / pathLength;
        
        // Calculate end position on path
        float targetPathPosition = pathPosition + jumpPercentage;
        targetPathPosition %= 1f; // Wrap around if needed

        // Get world positions for start and end
        Vector3 startPos = transform.position;
        Vector3 endPos = GetWorldPositionAtPathPosition(targetPathPosition);

        // Do the jump
        transform.DOJump(endPos, jumpPower, 1, jumpDuration)
            .SetEase(Ease.OutQuad)
            .OnUpdate(() => {
                // Update rotation during jump to face the landing direction
                if (faceMovementDirection)
                {
                    Vector3 jumpDirection = GetDirectionAtPathPosition(targetPathPosition);
                    if (jumpDirection != Vector3.zero)
                    {
                        Quaternion targetRot = Quaternion.LookRotation(jumpDirection);
                        transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime);
                    }
                }
            })
            .OnComplete(() => {
                // Update our path position to match where we jumped to
                pathPosition = targetPathPosition;
                isJumping = false;
                
                Debug.Log("Jump completed!");
                onJumpComplete?.Invoke();
                onJumpComplete = null;
            });
    }

    float CalculateTotalPathLength()
    {
        float totalLength = 0f;
        for (int i = 0; i < drawPoints.Length - 1; i++)
        {
            totalLength += Vector3.Distance(drawPoints[i], drawPoints[i + 1]);
        }
        return totalLength;
    }

    Vector3 GetWorldPositionAtPathPosition(float normalizedPos)
    {
        float floatIndex = normalizedPos * (drawPoints.Length - 1);
        int iA = Mathf.FloorToInt(floatIndex);
        int iB = Mathf.Min(iA + 1, drawPoints.Length - 1);
        float t = floatIndex - iA;

        return Vector3.Lerp(drawPoints[iA], drawPoints[iB], t);
    }

    Vector3 GetDirectionAtPathPosition(float normalizedPos)
    {
        float floatIndex = normalizedPos * (drawPoints.Length - 1);
        int iA = Mathf.FloorToInt(floatIndex);
        int iB = Mathf.Min(iA + 1, drawPoints.Length - 1);
        
        Vector3 direction = drawPoints[iB] - drawPoints[iA];
        direction.y = 0; // Keep only horizontal direction
        return direction.normalized;
    }

    public float GetCurrentSpeed()
    {
        return currentSpeed;
    }

    public bool IsJumping()
    {
        return isJumping;
    }

    public void GoToMainMenu()
    {
        SceneManager.LoadScene(0);
    }
    
}