using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;

public class GameEngine : MonoBehaviour
{
    [Header("Game Attributes")]
    public GameObject currentBlackHole;
    public GameObject currentPlayer;
    public static GameObject mainPlayer;
    public GameObject winCinematicGO;
    private PlayerHoverMovement _playerHoverMovement;
    private PlayerObjectShared _playerObjectShared;
    private BlackHoleManager _currentBlackHoleManager;
    public float arenaSize;

    [Header("Sound Elements")]
    public BackgroundMusicManager currentBGMManager;
    public AudioSource currentSFXAudioSource;
    public MenuAudioManager currentMenuAudioManager;
    public AudioClip lifeUpSFX;

    //public TMPro.TextMeshProUGUI coreCountText;

    [Header("Gameplay UI Elements")]
    public GameObject livesBar;
    public GameObject coresText;
    public GameObject coresBar;
    public GameObject coresFillBar;
    public GameObject boostStatus;
    public GameObject boostBar;
    public GameObject abilityDesc;
    public GameObject abilityStatus;
    public GameObject abilityBar;
    public GameObject scoreText;
    public GameObject levelText;
    public GameObject startTimeline;
    public GoTextFadeHelper goText;
    public GameObject jumpTextGO;

    private bool boostBarShown = false;
    private bool abilityBarShown = false;

    [Header("Pause Menu Elements")]
    public TMPro.TextMeshProUGUI versionText;
    public GameObject pauseMenu;
    public GameObject mainPausePanel;
    public GameObject optionsPanel;
    public GameObject confirmPanel;
    public static bool isPaused = true;
    public static bool playerPaused = false;
    public GameObject pauseMenuFirstItem;
    private GameObject _lastControlSelected;

    private float _prevTimeScale;

    public static bool gameStarted = false;
    private bool _musicSwappedA = false;

    private HiddenValueInt _lastScoreCheck;
    private HiddenValueInt _scorePerLifeUp;
    private bool _gameOverHit;
    private bool _playerJumped;
    private TimerHelper _playerJumpFlash;
    private bool _winCinematicDone;

    [Header("Dialog Elements")]
    public GameObject dialogMainUIGO;
    public float dialogDisplayTime;
    public AudioClip dialogSFXClip;
    public List<GameObject> dialogGOList;

    private List<bool> _dialogRanCheck = new List<bool>();
    private Queue<int> _dialogQueue = new Queue<int>();
    private int _currentDialogIndex;
    private TimerHelper _dialogTimer;
    private bool _dialogActive;

    private TimerHelper _bonusTimeLimit;    

    // Start is called before the first frame update
    void Awake()
    {
        // Make sure godmode is off when starting.
        GameManager.Instance.currentGameState = GameState.GAME;
        GameManager.Instance.godMode = false;
        GameManager.Instance.SetupLevel();

        // Get the current blackhole so we have easy access to its variables
        _currentBlackHoleManager = currentBlackHole.GetComponent<BlackHoleManager>();        
    }

    private void Start()
    {
        // Start the game, make sure the play GO is active
        //currentPlayer.SetActive(true);
        gameStarted = false;
        if (currentBGMManager)
        {
            currentBGMManager.StartAudioQueueAndPlay(0);
        }

        _playerHoverMovement = currentPlayer.GetComponent<PlayerHoverMovement>();
        _playerObjectShared = currentPlayer.GetComponent<PlayerObjectShared>();
        versionText.text = versionText.text.Replace("{versionNo}", GameManager.Instance.CurrentVersion);
        mainPlayer = currentPlayer;
        _prevTimeScale = 1.0f;
        _lastScoreCheck = new HiddenValueInt(0);
        _scorePerLifeUp = new HiddenValueInt(10000);
        currentPlayer.SetActive(false);
        startTimeline.SetActive(true);
        _gameOverHit = false;
        _playerJumped = false;
        _playerJumpFlash = new TimerHelper(0.5f);
        _winCinematicDone = false;
        _lastControlSelected = EventSystem.current.firstSelectedGameObject;

        for (int i = 0; i < dialogGOList.Count; i++)
        {
            _dialogRanCheck.Add(false);
        }

        _bonusTimeLimit = new TimerHelper(1200, false, TimerDirection.TimerDecrement);
    }

    public void StartGame()
    {
        currentPlayer.SetActive(true);
        isPaused = false;
        playerPaused = false;
        gameStarted = true;
        Destroy(startTimeline);
        currentBGMManager.CreateLoopQueue(1, 2, 3);
        goText.StartFade();
    }

    /// <summary>
    /// Gets the current blackhole radius 
    /// </summary>
    /// <returns>Current Blackhole size as a float</returns>
    public float GetCurrentBlackHoleRadius()
    {
        return _currentBlackHoleManager.currentBlackHoleRadius;
    }

    private void UpdateLifeBar()
    {
        if (livesBar != null)
        {
            for (int i = 0; i < 6; i++)
            {
                Transform currentLife = livesBar.transform.Find("Life" + i.ToString());
                if (currentLife != null)
                {
                    if (i <= GameManager.Instance.CurrentLives)
                    {
                        currentLife.gameObject.SetActive(true);
                    }
                    else
                    {
                        currentLife.gameObject.SetActive(false);
                    }
                }
            }

            Transform lifeOverflow = livesBar.transform.Find("LifeOverflow");
            if (lifeOverflow != null)
            {
                if (GameManager.Instance.CurrentLives > 5)
                {
                    lifeOverflow.gameObject.SetActive(true);
                    lifeOverflow.GetComponent<TMPro.TextMeshProUGUI>().text = "(+" + (GameManager.Instance.CurrentLives - 5).ToString() + ")";
                }
                else
                {
                    lifeOverflow.GetComponent<TMPro.TextMeshProUGUI>().text = "(+0)";
                    lifeOverflow.gameObject.SetActive(false);
                }
            }
        }
    }

    private void UpdateCoresBar()
    {
        float corePowerPercent = (float)GameManager.Instance.CurrentCores / (float)GameManager.Instance.CurrentNeededCores;

        if (coresText != null)
        {
            coresText.GetComponent<TMPro.TextMeshProUGUI>().text = "Core Power: " + Mathf.RoundToInt(corePowerPercent * 100.0f) + "%";
        }

        if (coresBar != null)
        {            
            if (coresFillBar != null)
            {
                RectTransform fillBarImage = coresFillBar.GetComponent<RectTransform>();
                RectTransform parentBar = fillBarImage.parent.GetComponent<RectTransform>();                
                float leftOffset = parentBar.rect.size.x - (parentBar.rect.size.x * corePowerPercent);                
                fillBarImage.offsetMin = new Vector2(leftOffset, 0);                
            }            
        }
    }

    private void UpdateScore()
    {
        if (scoreText != null)
        {
            scoreText.GetComponent<TMPro.TextMeshProUGUI>().text = GameManager.Instance.CurrentScore.ToString().PadLeft(9, '0');
        }
        int newLifeCheck = Mathf.FloorToInt(GameManager.Instance.CurrentScore / _scorePerLifeUp.Value);
        if (_lastScoreCheck.Value < newLifeCheck && !_gameOverHit)
        {
            GameManager.Instance.AddLife(newLifeCheck - _lastScoreCheck.Value);
            _lastScoreCheck.Value = newLifeCheck;
            if (lifeUpSFX != null)
            {
                currentSFXAudioSource.PlayOneShot(lifeUpSFX);
            }
        }
    }

    private void UpdateLevel()
    {
        if (levelText != null)
        {
            levelText.GetComponent<TMPro.TextMeshProUGUI>().text = (GameManager.Instance.CurrentLevel + 1).ToString().PadLeft(2, '0');
        }
    }

    private void UpdateBoostStatus()
    {
        if (boostStatus != null)
        {
            if (_playerHoverMovement != null)
            {
                if (_playerHoverMovement.BoostReady)
                {
                    boostStatus.SetActive(true);
                    boostBar.SetActive(false);
                    boostBarShown = false;
                }
                else
                {
                    if (boostBarShown)
                    {
                        if (boostBar != null)
                        {
                            Transform boostFillBar = boostBar.transform.Find("BoostBackgroundBar/BoostFillBar");
                            if (boostFillBar != null)
                            {
                                RectTransform fillBarImage = boostFillBar.gameObject.GetComponent<RectTransform>();
                                RectTransform parentBar = fillBarImage.parent.GetComponent<RectTransform>();
                                float rightOffset = -parentBar.rect.size.x + (parentBar.rect.size.x * _playerHoverMovement.BoostCooldownPosition);
                                fillBarImage.offsetMax = new Vector2(rightOffset, 0);
                                //fillBarImage.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, leftOffset);
                            }
                        }
                    }
                    else
                    {
                        boostStatus.SetActive(false);
                        boostBar.SetActive(true);
                        boostBarShown = true;
                    }
                }
            }
        }
    }

    private void UpdateAbilityBar()
    {
        if (_playerObjectShared.currentAbility != null)
        {
            if (abilityDesc != null)
            {
                abilityDesc.SetActive(true);
                abilityDesc.GetComponent<TMPro.TextMeshProUGUI>().text = _playerObjectShared.currentAbility.uiDescText;
            }

            if (abilityBar != null)
            {
                abilityStatus.GetComponent<TMPro.TextMeshProUGUI>().text = _playerObjectShared.currentAbility.uiReadyText;
                if (!_playerObjectShared.currentAbility.CooldownStatus)
                {
                    abilityStatus.SetActive(true);
                    abilityBar.SetActive(false);
                    abilityBarShown = false;
                }
                else
                {
                    if (abilityBarShown)
                    {
                        if (abilityBar != null)
                        {
                            Transform abilityFillBar = abilityBar.transform.Find("PowerBackgroundBar/PowerFillBar");
                            if (abilityFillBar != null)
                            {
                                RectTransform fillBarImage = abilityFillBar.gameObject.GetComponent<RectTransform>();
                                RectTransform parentBar = fillBarImage.parent.GetComponent<RectTransform>();                                
                                float leftOffset = parentBar.rect.size.x - (parentBar.rect.size.x * _playerObjectShared.currentAbility.CooldownTimePercent);
                                fillBarImage.offsetMin = new Vector2(leftOffset, 0);                                
                            }
                        }
                    }
                    else
                    {
                        abilityStatus.SetActive(false);
                        abilityBar.SetActive(true);
                        abilityBarShown = true;
                    }
                }
            }
        }
        else
        {
            abilityBar.SetActive(false);
            abilityStatus.SetActive(false);
            abilityDesc.SetActive(false);
            abilityBarShown = false;
        }
        
    }

    public void DoDialog(int dialogIndex, bool force = false)
    {
        if ((!_dialogActive && !_dialogRanCheck[dialogIndex]) || force)
        {
            _currentDialogIndex = dialogIndex;
            _dialogTimer = new TimerHelper(dialogDisplayTime, false);
            dialogMainUIGO.SetActive(true);
            dialogGOList[_currentDialogIndex].SetActive(true);            
            _dialogActive = true;
            if (dialogSFXClip != null)
            {
                currentSFXAudioSource.PlayOneShot(dialogSFXClip);
            }
        }
    }

    public void QueueDialog(int dialogIndex)
    {
        if (!_dialogRanCheck[dialogIndex])
        {
            if (_dialogActive)
            {
                _dialogQueue.Enqueue(dialogIndex);
            }
            else
            {
                DoDialog(dialogIndex);
            }
        }
    }

    private void CheckDialog(float currentTimeStamp)
    {
        if (_dialogActive)
        {
            if (_dialogTimer.HasTicked(currentTimeStamp))
            {
                _dialogRanCheck[_currentDialogIndex] = true;
                dialogGOList[_currentDialogIndex].SetActive(false);
                dialogMainUIGO.SetActive(false);
                _dialogTimer.RestartTimer();
                _dialogActive = false;
                if (_dialogQueue.Count > 0)
                {
                    DoDialog(_dialogQueue.Dequeue());
                }
            }
        }
    }

    // Update is called once per frame
    void LateUpdate()
    {
        if (gameStarted)
        {
            UpdateLifeBar();
            UpdateCoresBar();
            UpdateScore();
            UpdateLevel();
            UpdateBoostStatus();
            UpdateAbilityBar();

            if (GameManager.Instance.CurrentLevel == 3)
            {
                if (!_musicSwappedA)
                {
                    currentBGMManager.QueueIntroThenLoopQueue(4, 5, 6, 7, 6, 8);
                    _musicSwappedA = true;  
                }
            }
        }
    }

    void Update()
    {
        if (gameStarted)
        {
            CheckDialog(Time.deltaTime);

            if (Input.GetButtonDown("Cancel"))
            {
                if (!_gameOverHit)
                {
                    if (!isPaused)
                    {
                        isPaused = true;
                        pauseMenu.SetActive(true);
                        EventSystem.current.SetSelectedGameObject(pauseMenuFirstItem);
                        _lastControlSelected = pauseMenuFirstItem;
                        _prevTimeScale = Time.timeScale;
                        Time.timeScale = 0;
                    }
                    else
                    {
                        UnpauseGame();
                    }
                }
            }

            if (isPaused)
            {
                float horzIn = Input.GetAxisRaw("Horizontal");
                float vertIn = Input.GetAxisRaw("Vertical");

                if (horzIn != 0 || vertIn != 0)
                {
                    if (EventSystem.current.currentSelectedGameObject == null)
                    {
                        EventSystem.current.SetSelectedGameObject(pauseMenuFirstItem);
                    }                    
                }
            }

            if (!_playerJumped)
            {
                if (Input.GetButtonDown("Jump"))
                {
                    DoDialog(0);
                    _playerJumped = true;
                    jumpTextGO.SetActive(false);
                }
                else
                {
                    if (jumpTextGO != null)
                    {
                        if (_playerJumpFlash.HasTicked(Time.deltaTime))
                        {
                            jumpTextGO.SetActive(!jumpTextGO.activeSelf);
                        }
                    }
                }
            }

            if (!_gameOverHit)
            {
                if (GameManager.Instance.CurrentLevel >= 5)
                {
                    if (winCinematicGO != null)
                    {
                        winCinematicGO.transform.position = currentPlayer.transform.position;
                        winCinematicGO.transform.rotation = currentPlayer.transform.rotation;
                        winCinematicGO.SetActive(true);
                        currentPlayer.SetActive(false);
                    }
                    else
                    {
                        _winCinematicDone = true;
                    }
                    isPaused = true;
                    _gameOverHit = true;
                    CalcFinalScore(true);
                }

                if (GameManager.Instance.CurrentLives < 0)
                {
                    CalcFinalScore(false);
                    GameManager.Instance.DoGameOver();
                    _gameOverHit = true;
                }
            }
            else
            {
                if (_winCinematicDone)
                {
                    GameManager.Instance.DoGameWon();
                    _winCinematicDone = false;
                }
            }

            _bonusTimeLimit.HasTicked(Time.deltaTime);
        }
    }

    public void CalcFinalScore(bool wonGame)
    {
        int workingScore = GameManager.Instance.CurrentScore;
        workingScore += 10000 * GameManager.Instance.CurrentLevel;
        if (wonGame)
        {
            workingScore += 1000 * GameManager.Instance.CurrentLives;
            workingScore += 5000 * Mathf.FloorToInt(_bonusTimeLimit.Position * 100.0f);
        }
        GameManager.Instance.SetScore(workingScore);
    }

    public void FlagWin()
    {
        _winCinematicDone = true;
    }

    public void UnpauseGame()
    {
        isPaused = false;
        mainPausePanel.SetActive(true);
        optionsPanel.SetActive(false);
        confirmPanel.SetActive(false);
        pauseMenu.SetActive(false);
        Time.timeScale = _prevTimeScale;
    }

    public void SetupVolumeOptions()
    {
        // Gets the volume settings from the player profile and sets it in the game
        float currentMasterVol = PlayerPrefs.GetFloat("currentMasterVol");
        GameObject masterVolSliderGo = GameObject.Find("MainVolSlider");

        float currentMusicVol = PlayerPrefs.GetFloat("currentMusicVol");
        GameObject musicVolSliderGo = GameObject.Find("MusicVolSlider");

        float currentSFXVol = PlayerPrefs.GetFloat("currentSFXVol");
        GameObject SFXVolSliderGo = GameObject.Find("SfxVolSlider");

        masterVolSliderGo.GetComponent<Slider>().value = currentMasterVol;
        musicVolSliderGo.GetComponent<Slider>().value = currentMusicVol;
        SFXVolSliderGo.GetComponent<Slider>().value = currentSFXVol;
    }

    public void PlayMenuClick()
    {
        if (currentMenuAudioManager)
        {
            currentMenuAudioManager.PlayMenuClick();
        }
    }

    public void ResumeGame()
    {
        // Play the menu click sound if the audio manager is present
        if (currentMenuAudioManager)
        {
            currentMenuAudioManager.PlayMenuClick();
        }
        UnpauseGame();
    }

    public void Quit()
    {
        // Play the menu click sound if the audio manager is present
        if (currentMenuAudioManager)
        {
            currentMenuAudioManager.PlayMenuClick();
        }

        Time.timeScale = 1.0f;
        SceneManager.LoadSceneAsync("MainMenu");
    }

    public void SetMasterVolume(float value)
    {
        // Converts the master volume into decibels and stores it in the player profile
        GameManager.Instance.currentAudioMixer.SetFloat("masterVol", SharedMethods.ConvertToDecibels(value));
        PlayerPrefs.SetFloat("currentMasterVol", value);
    }

    public void SetMusicVolume(float value)
    {
        // Converts the music volume into decibels and stores it in the player profile
        GameManager.Instance.currentAudioMixer.SetFloat("musicVol", SharedMethods.ConvertToDecibels(value));
        PlayerPrefs.SetFloat("currentMusicVol", value);
    }

    public void SetSFXVolume(float value)
    {
        // Converts the sfx volume into decibels and stores it in the player profile
        GameManager.Instance.currentAudioMixer.SetFloat("sfxVol", SharedMethods.ConvertToDecibels(value));
        PlayerPrefs.SetFloat("currentSFXVol", value);
    }
}