using System;
using System.Collections;
using System.Collections.Generic;
using Febucci.UI;
using TMPro;
using Unity.Netcode;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class GameplayManager : NetworkBehaviour
{
    public static GameplayManager Instance { get; private set; }
    
    [SerializeField] private List<TextPopUpSO> TwoPointQuips;
    [SerializeField] private List<TextPopUpSO> ThreePointQuips;
    [SerializeField] private List<TextPopUpSO> DefenseQuips;
    [SerializeField] private TextMeshProUGUI homeScore;
    [SerializeField] private TextMeshProUGUI awayScore;
    [SerializeField] private TextMeshProUGUI homeQuipText;
    [SerializeField] private TextMeshProUGUI awayQuipText;
    [SerializeField] private Button ReadyBtn;

    [SerializeField]
    private TypewriterByCharacter _typewriterByCharacter;

    private Dictionary<ulong, bool> playerReadyDictionary;

    public event EventHandler OnStateChanged;
    public event EventHandler OnLocalPlayerReadyChanged;
    
    private enum State
    {
        WaitingToStart,
        CountdownToStart,
        GamePlaying,
        GameOver,
    }

    private float waitingToStartTimer = 1f;
    private float countdownToStartTimer = 3f;
    private float gamePlayingTimer = 10f;
    private bool isLocalPlayerReady = false;
    

    private State state;
    private static double homeLevel;
    private static double awayLevel;
    private double homeTeamScore;
    private double awayTeamScore;
    private int homeFinalScore;
    private int awayFinalScore;
    private double pFactor;
    private float cFactor = 0.90f;
    private System.Random _random = new System.Random();

    private void Update()
    {
        switch (state)
        {
            case State.WaitingToStart:
                break;
            case State.CountdownToStart:
                countdownToStartTimer -= Time.deltaTime;
                if (countdownToStartTimer < 0f)
                {
                    state = State.GamePlaying;
                    OnStateChanged?.Invoke(this,EventArgs.Empty);
                }
                break;
            case State.GamePlaying:
                gamePlayingTimer -= Time.deltaTime;
                if (gamePlayingTimer < 0f)
                {
                    state = State.GameOver;
                    OnStateChanged?.Invoke(this,EventArgs.Empty);
                }
                break;
            case State.GameOver:
                break;
        }
        //Debug.Log(state);
    }

    public bool IsGamePlaying()
    {
        return state == State.GamePlaying;
    }

    public bool IsCountdownToStartActive()
    {
        return state == State.CountdownToStart;
    }

    public bool IsGameOver()
    {
        return state == State.GameOver;
    }

    public float GetCountdownToStartTimer()
    {
        return countdownToStartTimer;
    }
    public static void setHomeLevel(double level)
    {
        homeLevel = level;
    }
    
    public static void setAwayLevel(double level)
    {
        awayLevel = level;
    }

    private double calculateTeamScore100(double teamLevel)
    {
        if (!NetworkManager.Singleton.IsServer)
        {
            Debug.Log("NOT SERVER Team100");
            return 0;
        }
        pFactor = _random.NextDouble();
        Debug.Log("P factor " + pFactor);
        double tmpScore = Math.Pow(pFactor, (1 - (teamLevel / cFactor) / 100)) * 100;
        Debug.Log("Team Score " + tmpScore);
        return tmpScore;

    }

    private void calculateWinner(double homeScore, double awayScore)
    {
        if (!NetworkManager.Singleton.IsServer)
        {
            Debug.Log("NOT SERVER Winner");
            return;
        }
        if (homeScore >= awayScore)
        {
            homeFinalScore = 21;
            awayFinalScore = (int)(awayScore / homeScore * 21);
            if (awayFinalScore == 20)
            {
                homeFinalScore = 22;
            }
            Debug.Log("Home: " + homeFinalScore + " Away: " + awayFinalScore);
        }
        else
        {
            awayFinalScore = 21;
            homeFinalScore = (int)(homeScore / awayScore * 21);
            if (homeFinalScore == 20)
            {
                awayFinalScore = 22;
            }
            Debug.Log("Home: " + homeFinalScore + " Away: " + awayFinalScore);
        }
    }

    /*private double calculateTeamLevel(string nft1, string nft2, string nft3)
    {
        double total = 0f;
        double teamValue = 0f;
        total += NFTStats.getNFTScore(nft1);
        Debug.Log("Total: " + total);
        total += NFTStats.getNFTScore(nft2);
        Debug.Log("Total: " + total);
        total += NFTStats.getNFTScore(nft3);
        Debug.Log("Total: " + total);
        teamValue = total / 3;
        Debug.Log("Team: " + teamValue);
        return teamValue;
    }*/

    private IEnumerator gameSimulation()
    {
        int runningHomeScore = 0;
        int runningAwayScore = 0;
        yield return new WaitForSeconds(4);
        
        while ((runningHomeScore != homeFinalScore) || (runningAwayScore != awayFinalScore))
        {
            if (runningHomeScore < 21 && runningAwayScore < 21)
            {
                double posessionPicker = _random.NextDouble();
                double defensivePicker = _random.NextDouble();
                if (posessionPicker <= 0.5f)
                {
                    if (posessionPicker <= 0.3f && (homeFinalScore - runningHomeScore) >= 1)
                    {
                        if (defensivePicker <= 0.1f)
                        {
                            int indexOfQuip = _random.Next(DefenseQuips.Count);
                            _typewriterByCharacter.ShowText("{rdir} <wave>" + DefenseQuips[indexOfQuip].getText() + "</wave> {#rdir}");
                            _typewriterByCharacter.StartShowingText(true);
                            homeQuipText.alpha = 1.0f;
                            yield return new WaitForSeconds(4);
                            _typewriterByCharacter.StartDisappearingText();
                            homeQuipText.alpha = 0.0f;
                        }
                        else
                        {
                            if (runningHomeScore + 1 >= 21 && runningAwayScore != awayFinalScore)
                            {
                                continue;
                            }
                            int indexOfQuip = _random.Next(TwoPointQuips.Count);
                            _typewriterByCharacter.ShowText("{rdir} <bounce>" + TwoPointQuips[indexOfQuip].getText() + "/<bounce> {#rdir}");
                            _typewriterByCharacter.StartShowingText(true);
                            //homeQuipText.text = "{vertexp} <bounce>" + TwoPointQuips[indexOfQuip].getText() + "/<bounce> {#rot}";
                            homeQuipText.alpha = 1.0f;
                            runningHomeScore += 1;
                            homeScore.text = runningHomeScore.ToString();
                            yield return new WaitForSeconds(4);
                            hideText(homeQuipText);
                        }
                    }
                    else if (posessionPicker > 0.3f && (homeFinalScore - runningHomeScore) >= 2)
                    {
                        if (defensivePicker <= 0.1f)
                        {
                            int indexOfQuip = _random.Next(DefenseQuips.Count);
                            _typewriterByCharacter.ShowText("{rdir}<incr>" + DefenseQuips[indexOfQuip].getText() + "</incr>{#rdir}");
                            _typewriterByCharacter.StartShowingText(true);
                            homeQuipText.alpha = 1.0f;
                            yield return new WaitForSeconds(4);
                            _typewriterByCharacter.StartDisappearingText();
                            homeQuipText.alpha = 0.0f;
                        }
                        else
                        {
                            if (runningHomeScore + 2 >= 21 && runningAwayScore != awayFinalScore)
                            {
                                continue;
                            }
                            int indexOfQuip = _random.Next(ThreePointQuips.Count);
                            _typewriterByCharacter.ShowText("{rdir}<slide>" + ThreePointQuips[indexOfQuip].getText() + "{#rdir}");
                            _typewriterByCharacter.StartShowingText(true);
                            homeQuipText.alpha = 1.0f;
                            runningHomeScore += 2;
                            homeScore.text = runningHomeScore.ToString();
                            yield return new WaitForSeconds(4);
                            _typewriterByCharacter.StartDisappearingText();
                            homeQuipText.alpha = 0.0f;
                        }
                    }
                    else
                    {
                        if (runningHomeScore != homeFinalScore)
                        {
                            if (defensivePicker <= 0.1f)
                            {
                                int indexOfQuip = _random.Next(DefenseQuips.Count);
                                _typewriterByCharacter.ShowText("{rdir}<wave>" + DefenseQuips[indexOfQuip].getText() + "</wave>{#rdir}");
                                _typewriterByCharacter.StartShowingText(true);
                                homeQuipText.alpha = 1.0f;
                                yield return new WaitForSeconds(4);
                                _typewriterByCharacter.StartDisappearingText();
                            }
                            else
                            {
                                if (runningHomeScore + 1 >= 21 && runningAwayScore != awayFinalScore)
                                {
                                    continue;
                                }
                                int indexOfQuip = _random.Next(TwoPointQuips.Count);
                                _typewriterByCharacter.ShowText("{rdir}<bounce>" + TwoPointQuips[indexOfQuip].getText() + "</bounce>{#rdir}");
                                _typewriterByCharacter.StartShowingText(true);
                                homeQuipText.alpha = 1.0f;
                                runningHomeScore += 1;
                                homeScore.text = runningHomeScore.ToString();
                                yield return new WaitForSeconds(4);
                                _typewriterByCharacter.StartDisappearingText();
                                homeQuipText.alpha = 0.0f;
                            }
                        }
                        else
                        {
                            Debug.Log("REACHED TARGET");
                        }
                    }
                }
                else if (posessionPicker > 0.5f)
                {
                    if (posessionPicker <= 0.8f && (awayFinalScore - runningAwayScore) >= 1)
                    {
                        if (defensivePicker <= 0.1f)
                        {
                            int indexOfQuip = _random.Next(DefenseQuips.Count);
                            awayQuipText.text = DefenseQuips[indexOfQuip].getText();
                            awayQuipText.alpha = 1.0f;
                            yield return new WaitForSeconds(4);
                            awayQuipText.alpha = 0.0f;
                        }
                        else
                        {
                            if (runningAwayScore + 1 >= 21 && runningHomeScore != homeFinalScore)
                            {
                                continue;
                            }
                            int indexOfQuip = _random.Next(TwoPointQuips.Count);
                            awayQuipText.text = TwoPointQuips[indexOfQuip].getText();
                            awayQuipText.alpha = 1.0f;
                            runningAwayScore += 1;
                            awayScore.text = runningAwayScore.ToString();
                            yield return new WaitForSeconds(4);
                            awayQuipText.alpha = 0.0f;
                        }
                    }
                    else if (posessionPicker > 0.8f && (awayFinalScore - runningAwayScore) >= 2)
                    {
                        if (defensivePicker <= 0.1f)
                        {
                            int indexOfQuip = _random.Next(DefenseQuips.Count);
                            awayQuipText.text = DefenseQuips[indexOfQuip].getText();
                            awayQuipText.alpha = 1.0f;
                            yield return new WaitForSeconds(4);
                            awayQuipText.alpha = 0.0f;
                        }
                        else
                        {
                            if (runningAwayScore + 2 >= 21 && runningHomeScore != homeFinalScore)
                            {
                                continue;
                            }
                            int indexOfQuip = _random.Next(ThreePointQuips.Count);
                            awayQuipText.text = ThreePointQuips[indexOfQuip].getText();
                            awayQuipText.alpha = 1.0f;
                            runningAwayScore += 2;
                            awayScore.text = runningAwayScore.ToString();
                            yield return new WaitForSeconds(4);
                            awayQuipText.alpha = 0.0f;
                        }
                    }
                    else
                    {
                        if (runningAwayScore != awayFinalScore)
                        {
                            if (defensivePicker <= 0.1f)
                            {
                                int indexOfQuip = _random.Next(DefenseQuips.Count);
                                awayQuipText.text = DefenseQuips[indexOfQuip].getText();
                                awayQuipText.alpha = 1.0f;
                                yield return new WaitForSeconds(4);
                                awayQuipText.alpha = 0.0f;
                            }
                            else
                            {
                                if (runningAwayScore + 1 >= 21 && runningHomeScore != homeFinalScore)
                                {
                                    continue;
                                }
                                int indexOfQuip = _random.Next(TwoPointQuips.Count);
                                awayQuipText.text = TwoPointQuips[indexOfQuip].getText();
                                awayQuipText.alpha = 1.0f;
                                runningAwayScore += 1;
                                awayScore.text = runningAwayScore.ToString();
                                yield return new WaitForSeconds(4);
                                awayQuipText.alpha = 0.0f;
                            }
                        }
                        else
                        {
                            Debug.Log("REACHED TARGET");
                        }
                    }
                }
            }
            else
            {
                break;
            }
        }
    }

    private void OnEnable()
    {
        Instance = this;
        ReadyBtn.onClick.AddListener(ReadyToPlay);
        state = State.WaitingToStart;
        playerReadyDictionary = new Dictionary<ulong, bool>();
        if (NetworkManager.Singleton.IsServer)
        {
            print("IS SERVER");
        }

        if (NetworkManager.Singleton.IsClient)
        {
            print("IS CLIENT");
        }
        
        if(NetworkManager.Singleton.IsHost)
        {
            print("IS HOST");
        }
        TestClientRpc();
        TestServerRpc();
        if (!NetworkManager.Singleton.IsServer)
        {
            print("NOT SERVER");
            return;
        }
        //homeLevel = calculateTeamLevel("NFT LEAGUEZ #997", "NFT LEAGUEZ #347", "NFT LEAGUEZ #397");
        //awayLevel = calculateTeamLevel("NFT LEAGUEZ #450", "NFT LEAGUEZ #597", "NFT LEAGUEZ #577");
        homeTeamScore = calculateTeamScore100(homeLevel);
        awayTeamScore = calculateTeamScore100(awayLevel);
        calculateWinner(homeTeamScore, awayTeamScore);
        StartCoroutine(gameSimulation());
    }

    private void OnDisable()
    {
        int zero = 0;
        homeScore.text = zero.ToString();
        awayScore.text = zero.ToString();
    }

    public void hideText(TextMeshProUGUI text)
    {
        _typewriterByCharacter.StartDisappearingText();
        text.alpha = 0.0f;
    }

    public string GetHomeScore()
    {
        return homeScore.text;
    }
    
    public string GetAwayScore()
    {
        return awayScore.text;
    }

    private void ReadyToPlay()
    {
        isLocalPlayerReady = true;
        OnLocalPlayerReadyChanged?.Invoke(this, EventArgs.Empty);
        Debug.Log("CALLING RPC ");
        SetPlayerReadyServerRpc();
        Debug.Log("FINISH RPC ");
    }

    [ServerRpc(RequireOwnership = false)]
    private void SetPlayerReadyServerRpc(ServerRpcParams serverRpcParams = default)
    {
        Debug.Log("IN SERVER RPC, ID: ");
        Debug.Log(serverRpcParams.Receive.SenderClientId);
        playerReadyDictionary[serverRpcParams.Receive.SenderClientId] = true;

        bool allClientsReady = true;
        foreach (ulong clientId in NetworkManager.Singleton.ConnectedClientsIds)
        {
            if (!playerReadyDictionary.ContainsKey(clientId) || !playerReadyDictionary[clientId])
            {
                //Player not ready
                allClientsReady = false;
                break;
            }
        }
        
        Debug.Log("All players ready: " + allClientsReady);
    }

    [ServerRpc(RequireOwnership = false)]
    private void TestServerRpc(ServerRpcParams serverRpcParams = default)
    {
        Debug.Log("TEST SERVER RPC");
    }

    [ClientRpc]
    private void TestClientRpc(ClientRpcParams clientRpcParams = default)
    {
        Debug.Log("TEST CLIENT RPC");
    }

    public bool isLocalPlayerReadyToPlay()
    {
        return isLocalPlayerReady;
    }
}