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

public enum EnemyTypeName
{
    ENEMYDUMB,
    ENEMYCOWARD,
    ENEMYCHASE,
    ENEMYDROP
}

public enum GameState
{
    MAINMENU,
    RULESMENU,
    GAME,
    DEATHMENU,
    WINMENU
}

public class GameManager : MonoBehaviour
{
    private static GameManager _instance;
    public static GameManager Instance
    {
        get
        {
            return _instance;
        }
    }

    // Dictionary to hold the enemy counts and type
    public Dictionary<EnemyTypeName, EnemyType> enemyList = new Dictionary<EnemyTypeName, EnemyType>();

    public AudioMixer currentAudioMixer;

    public bool godMode = false;

    private HiddenValueInt _startingLives = new HiddenValueInt(5);
    private HiddenValueInt _lives = new HiddenValueInt(0);

    private int _firstLevel = 0;
    private HiddenValueInt _level = new HiddenValueInt(0);

    public int blackHoleSize = 0;

    private int _startCores = 0;
    private HiddenValueInt _coreCount = new HiddenValueInt(0);
    private List<HiddenValueInt> _coresNeeded = new List<HiddenValueInt>();

    private HiddenValueInt _score = new HiddenValueInt(0);

    public bool boss = false;
    public bool isGameOver = false;

    public GameState currentGameState;
    public bool warmStart = false;

    private int _versionMajor = 0;
    private int _versionMinor = 2;
    private int _versionRevision = 4;

    public string CurrentVersion
    {
        get
        {
            return _versionMajor.ToString() + "." + _versionMinor.ToString() + "." + _versionRevision.ToString();
        }
    }

    public int CurrentLevel
    {
        get
        {
            return _level.Value;
        }
    }

    public int CurrentLives
    {
        get
        {
            return _lives.Value;
        }
    }

    public int CurrentCores
    {
        get
        {
            return _coreCount.Value;
        }
    }

    public int CurrentScore
    {
        get
        {
            return _score.Value;
        }
    }

    public int CurrentNeededCores
    {
        get
        {
            int result;

            if (CurrentLevel == 5)
            {
                result = _coreCount.Value;
            }

            if (CurrentLevel == -1)
            {
                result = -1;
            }
            else if (_coresNeeded.Count <= CurrentLevel) 
            {
                result = _coresNeeded[_coresNeeded.Count - 1].Value;
            }
            else
            {
                result = _coresNeeded[CurrentLevel].Value;
            }
            return result;
        }
    }

    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }

    private void Start()
    {        
        // Load the saved audio levels into the mixer
        if (PlayerPrefs.HasKey("currentMasterVol"))
        {
            float currentMasterVol = PlayerPrefs.GetFloat("currentMasterVol");
            float currentMusicVol = PlayerPrefs.GetFloat("currentMusicVol");
            float currentSFXVol = PlayerPrefs.GetFloat("currentSFXVol");

            currentAudioMixer.SetFloat("masterVol", SharedMethods.ConvertToDecibels(currentMasterVol));
            currentAudioMixer.SetFloat("musicVol", SharedMethods.ConvertToDecibels(currentMusicVol));
            currentAudioMixer.SetFloat("sfxVol", SharedMethods.ConvertToDecibels(currentSFXVol));
        }
        else
        {
            float currentMasterVol = 1.0f;
            float currentMusicVol = 0.5f;
            float currentSFXVol = 0.8f;

            currentAudioMixer.SetFloat("masterVol", SharedMethods.ConvertToDecibels(currentMasterVol));
            currentAudioMixer.SetFloat("musicVol", SharedMethods.ConvertToDecibels(currentMusicVol));
            currentAudioMixer.SetFloat("sfxVol", SharedMethods.ConvertToDecibels(currentSFXVol));

            PlayerPrefs.SetFloat("currentMasterVol", currentMasterVol);
            PlayerPrefs.SetFloat("currentMusicVol", currentMusicVol);
            PlayerPrefs.SetFloat("currentSFXVol", currentSFXVol);
        }

    }

    public void ResetStats()
    {
        _lives.Value = _startingLives.Value;
        _coreCount.Value = _startCores;
        _level.Value = _firstLevel;
        _score.Value = 0;
        isGameOver = false;
    }

    public void SetupLevel()
    {
        if (warmStart)
        {
            ResetStats();
            warmStart = false;
        }

        if (_coresNeeded.Count == 0)
        {
            _coresNeeded.Add(new HiddenValueInt(4));
            _coresNeeded.Add(new HiddenValueInt(6));
            _coresNeeded.Add(new HiddenValueInt(12));
            _coresNeeded.Add(new HiddenValueInt(16));
            _coresNeeded.Add(new HiddenValueInt(20));
        }

        if (enemyList.Count == 0)
        {
            // Set up the enemy level and count dictionaries
            EnemyType enemyDumbSetup = new EnemyType();
            EnemyType enemyCowardSetup = new EnemyType();
            EnemyType enemyChaseSetup = new EnemyType();
            EnemyType enemyDropSetup = new EnemyType();

            // Level 1 numbers
            enemyDumbSetup.AddLevelStats(0, 15, 500, 300.0f, 10.0f);
            enemyCowardSetup.AddLevelStats(0, 1, 1500, 300.0f, 10.0f);
            enemyChaseSetup.AddLevelStats(0, 0, 0, 0.0f, 0.0f);
            enemyDropSetup.AddLevelStats(0, 0, 0, 0.0f, 0.0f);

            // Level 2 numbers
            enemyDumbSetup.AddLevelStats(1, 20, 450, 240.0f, 20.0f);
            enemyCowardSetup.AddLevelStats(1, 5, 1000, 300.0f, 10.0f);
            enemyChaseSetup.AddLevelStats(1, 0, 0, 0.0f, 0.0f);
            enemyDropSetup.AddLevelStats(1, 0, 0, 0.0f, 0.0f);

            // Level 3 numbers
            enemyDumbSetup.AddLevelStats(2, 20, 200, 180.0f, 40.0f);
            enemyCowardSetup.AddLevelStats(2, 8, 500, 240.0f, 20.0f);
            enemyChaseSetup.AddLevelStats(2, 2, 1500, 360.0f, 5.0f);
            enemyDropSetup.AddLevelStats(2, 0, 0, 0.0f, 0.0f);

            // Level 4 numbers
            enemyDumbSetup.AddLevelStats(3, 25, 150, 180.0f, 50.0f);
            enemyCowardSetup.AddLevelStats(3, 10, 500, 240.0f, 30.0f);
            enemyChaseSetup.AddLevelStats(3, 5, 1000, 300.0f, 20.0f);
            enemyDropSetup.AddLevelStats(3, 2, 2000, 300.0f, 10.0f);            

            // Add the counts to the enemy type dictionaries
            enemyList.Add(EnemyTypeName.ENEMYDUMB, enemyDumbSetup);
            enemyList.Add(EnemyTypeName.ENEMYCOWARD, enemyCowardSetup);
            enemyList.Add(EnemyTypeName.ENEMYCHASE, enemyChaseSetup);
            enemyList.Add(EnemyTypeName.ENEMYDROP, enemyDropSetup);
        }
    }

    public EnemyType.EnemyTypeStat GetCurrentLevelEnemyStats(EnemyTypeName enemyType)
    {
        if (enemyList[enemyType][CurrentLevel] == null)
        {
            // Get the "last" levels numbers
            return enemyList[enemyType][enemyList[enemyType].Count - 1];
        }
        else
        {
            return enemyList[enemyType][CurrentLevel];
        }
    }

    public int GetCurrentLevelEnemyTypeCount(EnemyTypeName enemyType)
    {
        int result;
        // Check if the current level is higher than the max we have set up (we should probs cap it)
        if (enemyList[enemyType][CurrentLevel] == null)
        {
            // Get the "last" levels numbers
            result = enemyList[enemyType][enemyList[enemyType].Count - 1].SpawnCount;
        }
        else
        {
            // Get the current levels numbers
            result = enemyList[enemyType][CurrentLevel].SpawnCount;
        }

        return result;
    }

    // Update is called once per frame
    void LateUpdate()
    {
        if (currentGameState == GameState.GAME)
        {
            if (CurrentCores >= CurrentNeededCores)
            {
                _coreCount.Value = 0;
                _level += 1;
            }
        }
    }
      
    public void AddScore(int amount)
    {
        _score.Value = Mathf.Clamp(CurrentScore + amount, 0, 999999999);
    }

    public void SetScore(int amount)
    {
        _score.Value = Mathf.Clamp(amount, 0, 999999999);
    }

    public void WarpLevels(int amount)
    {
        _level += amount;
    }

    public void LostLife()
    {
        _lives -= 1;                
    }

    public void AddCore(int amount = 1)
    {
        _coreCount += amount;
    }

    public void AddLife(int amount = 1)
    {
        _lives.Value = Mathf.Clamp(CurrentLives + amount, -1, 99);
    }
    public void DoGameOver()
    {
        isGameOver = true;        
        SceneManager.LoadSceneAsync("Dead");
    }

    public void DoGameWon()
    {        
        isGameOver = true;
        SceneManager.LoadSceneAsync("Win");
    }
}
