using UnityEngine;
using TMPro;
using System.Collections;
using System.Collections.Generic;
using Unity.Cinemachine;

public class RaceManager : MonoBehaviour
{
    public static RaceManager Instance;

    [Header("Race Settings")]
    public int totalLaps = 3;
    public int numberOfCheckpoints = 0;

    [Header("Countdown Settings")]
    public int preliminaryCounts = 3;
    public float delayBetweenCounts = 1.0f;
    public AudioSource countAudioSource;
    public AudioSource startSignalAudioSource;
    public TextMeshProUGUI countdownText;

    [Header("Finish Line Settings")]
    public Transform finishLine;

    [Header("UI Elements")]
    public TextMeshProUGUI playerPositionText;
    public TextMeshProUGUI lapsLeftText;
    public GameObject playerVehicle;

    [Header("Post-Race Settings")]
    public CinemachineCamera victoryCamera;
    public CinemachineCamera playerCamera;
    public GameObject postRaceCanvas;
    public TextMeshProUGUI victoryText;
    public GameObject playerUI;

    private List<RacerProgress> racers = new List<RacerProgress>();
    public bool raceFinished = false;
    public bool raceStarted = false;
    public string winnerName = "";

    private RacerProgress playerProgress;
    private string[] placeMapping = { "1st", "2nd", "3rd" };

    void Awake()
    {
        if (Instance == null)
            Instance = this;
        else
            Destroy(gameObject);
    }

    void Start()
    {
        GameObject[] racerObjects = GameObject.FindGameObjectsWithTag("Racer");
        foreach (GameObject racer in racerObjects)
        {
            RacerProgress progress = racer.GetComponent<RacerProgress>();
            if (progress != null)
            {
                racers.Add(progress);
            }
        }

        if (playerVehicle != null) 
        {
            playerProgress = playerVehicle.GetComponent<RacerProgress>();
        }

        if (postRaceCanvas != null)
            postRaceCanvas.SetActive(false);

        LockRacers();
        StartCoroutine(RaceCountdown());
    }

    void Update()
    {
        if (playerProgress != null && raceStarted && !raceFinished)
        {
            int playerPosition = GetPlayerPosition();
            UpdatePositionUI(playerPosition);
            UpdateLapsLeftUI();
        }
    }

    private IEnumerator RaceCountdown()
    {
        if (countdownText != null) countdownText.gameObject.SetActive(true);

        for (int i = preliminaryCounts; i > 0; i--)
        {
            if (countAudioSource != null) countAudioSource.Play();
            if (countdownText != null) countdownText.text = i.ToString();
            yield return new WaitForSeconds(delayBetweenCounts);
        }

        if (startSignalAudioSource != null) startSignalAudioSource.Play();
        if (countdownText != null) countdownText.text = "GO!";
        
        yield return new WaitForSeconds(1f);  // Display "GO!" briefly
        if (countdownText != null) countdownText.gameObject.SetActive(false);

        UnlockRacers();
        raceStarted = true;
    }

    private void LockRacers()
    {
        foreach (RacerProgress racer in racers)
        {
            BaseHovercarController controller = racer.GetComponent<BaseHovercarController>();
            if (controller != null)
            {
                controller.enabled = false; // Disable the movement script.
            }

            Rigidbody rb = racer.GetComponent<Rigidbody>();
            if (rb != null)
            {
                rb.linearVelocity = Vector3.zero;
                rb.angularVelocity = Vector3.zero;
                rb.constraints = RigidbodyConstraints.FreezePosition | RigidbodyConstraints.FreezeRotation;
            }
        }
    }

    private void UnlockRacers()
    {
        foreach (RacerProgress racer in racers)
        {
            BaseHovercarController controller = racer.GetComponent<BaseHovercarController>();
            if (controller != null)
            {
                controller.enabled = true; // Disable the movement script.
            }

            racer.GetComponent<BaseHovercarController>().canAccelerate = true;
            Rigidbody rb = racer.GetComponent<Rigidbody>();
            if (rb != null)
            {
                rb.constraints = RigidbodyConstraints.None;
            }
        }
    }

    private int GetPlayerPosition()
    {
        racers.Sort((r1, r2) => GetRacerProgressValue(r2).CompareTo(GetRacerProgressValue(r1)));
        for (int i = 0; i < racers.Count; i++)
        {
            if (racers[i] == playerProgress)
                return i + 1;
        }
        return racers.Count;
    }

    private void UpdatePositionUI(int position)
    {
        playerPositionText.text = GetPrettyPosition(position);
    }

    private string GetPrettyPosition(int position)
    {
        if (position < 4) 
        {
            return placeMapping[position - 1];
        } 
        else 
        {
            return position + "th";
        }
    }

    private void UpdateLapsLeftUI()
    {
        int lapsLeft = Mathf.Max(totalLaps - playerProgress.lapCount, 0);
        lapsLeftText.text = "Laps Left: " + lapsLeft;
    }

    private float GetRacerProgressValue(RacerProgress rp)
    {
        return rp.lapCount * numberOfCheckpoints + rp.currentCheckpointIndex;
    }

    public void CheckFinish(RacerProgress rp)
    {
        if (rp.lapCount >= totalLaps && !raceFinished)
        {
            raceFinished = true;
            winnerName = rp.gameObject.name;
            Debug.Log("Race Finished! Winner: " + winnerName);
            TriggerPostRaceEvents();
        }
    }

    private void TriggerPostRaceEvents()
    {
        LockRacers();
        if (victoryCamera != null && playerVehicle != null && playerCamera != null)
        {
            victoryCamera.gameObject.SetActive(true);
            playerCamera.gameObject.SetActive(false);
        }

        if (postRaceCanvas != null) 
        {
            int playerPosition = GetPlayerPosition();
            postRaceCanvas.SetActive(true);
            if (playerPosition == 1) {
                victoryText.text = "You win";
            }
            else 
            {
                victoryText.text = "you placed " + GetPrettyPosition(playerPosition);
            }
        }
        if (playerUI != null) playerUI.SetActive(false);
    }
}
