using System.Collections;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;

public class BattleManager : MonoBehaviour
{
    private const string EnemyColor = "#ff06de";
    private const string DamageColor = "#ff9924";
    public static BattleManager Instance;
    public GameObject MessageBox;
    public TypingText MessageBoxText;
    public Player HumanPlayer;
    public Enemy CurrentEnemy => _currentEnemy;
    public GameObject EnemyHolder;
    public GameObject PlayerBattleActions;
    public GameObject PlayerInventory;
    public InfoMeter EnemyInfo;
    
    public MapLocation.TerrainType CurrentTerrain;

    public GameObject Grassland;
    public GameObject Snowland;
    public GameObject Sandland;

    public GameObject BubbleAttack;
    public GameObject SlapAttack;
    public GameObject SparkAttack;
    
    private Enemy _currentEnemy;
    private int _turnNumber = 0;
    private bool _isPlayerTurn = true;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
    }

    private void OnEnable()
    {
        MessageBox.SetActive(true);
    }

    private void OnDisable()
    {
        MessageBox.SetActive(false);
    }

    public void InitBattle(Enemy enemy)
    {
        SetTerrain();
        
        foreach(Transform child in EnemyHolder.transform)
        {
            Destroy(child.gameObject);
        }

        _currentEnemy = Instantiate(enemy, EnemyHolder.transform.position, quaternion.identity);
        _currentEnemy.Info = EnemyInfo;
        EnemyInfo.UpdateInfo(_currentEnemy);
        _currentEnemy.transform.parent = EnemyHolder.transform;
        _currentEnemy.transform.rotation = Quaternion.AngleAxis(180, Vector3.down);
        
        //MessageBoxText.ShowText("you encounter a <color=" + EnemyColor + ">" + _currentEnemy.Name + "</color>!", () =>
        MessageBoxText.ShowText("you encounter a " + _currentEnemy.Name + "!", () =>
        {
            _currentEnemy.Info.UpdateInfo(_currentEnemy);
            StartCoroutine(WaitForClick(PlayerTurn));
        });
    }
    
    private void SetTerrain()
    {
        switch (CurrentTerrain)
        {
            case MapLocation.TerrainType.Grass:
            {
                SetGrassland();
                break;
            }
            case MapLocation.TerrainType.Sand:
            {
                SetSandland();
                break;
            }
            case MapLocation.TerrainType.Snow:
            {
                SetSnowland();
                break;
            }
        }
    }
    
    private void ShowPlayerActions()
    {
        PlayerBattleActions.gameObject.SetActive(true);
    }

    private void PlayerTurn()
    {
        ShowPlayerActions();
    }

    private IEnumerator WaitForClick(UnityAction done)
    {
        while (!Input.GetMouseButtonUp(0))
        {
            yield return null;
        }
        done.Invoke();
    }

    public void Attack()
    {
        GameObject attack = Instantiate(SlapAttack, EnemyHolder.transform.position, Quaternion.identity);
        StartCoroutine(Delay(1, () =>
        {
            Destroy(attack.gameObject);
        }));
        PlayerBattleActions.SetActive(false);
        int atk = HumanPlayer.Attack(_currentEnemy);
        MessageBoxText.ShowText("you attack for " + atk + " damage!", () =>
        {
            StartCoroutine(WaitForClick(PassTurnToAI));
        });
    }

    public void Defend()
    {
        PlayerBattleActions.SetActive(false);
        HumanPlayer.DecrementHP( -HumanPlayer.Stat.DEF );
        MessageBoxText.ShowText("you take up a defensive position and heal " + HumanPlayer.Stat.DEF + " hp!", () => PassTurnToAI());
    }

    public void ShowItems()
    {
        PlayerBattleActions.SetActive(false);
        Item item = HumanPlayer.GetItem();

        if (item.Damage > 0)
        {
            _currentEnemy.DecrementHP(item.Damage);
        }
        MessageBoxText.ShowText(item.Message, () =>
        {
            StartCoroutine(WaitForClick(() =>
            {
                PassTurnToAI();
            }));
        });
    }


    private void PassTurnToAI()
    {
        StartCoroutine(Delay(1, () =>
        {
            if (_currentEnemy.IsDead())
            {
                WinBattle();
            }
            else
            {
                EnemyTurn();
            }
        }));
    }

    public IEnumerator Delay(float delay, UnityAction done)
    {
        yield return new WaitForSeconds(delay);
        done.Invoke();
    }

    private void EnemyTurn()
    {
        _currentEnemy.TakeAction(HumanPlayer, PassTurn);

        void PassTurn()
        {
            if (HumanPlayer.IsDead())
            {
                LoseBattle();
            }
            else
            {
                PlayerTurn();
            }
        }
    }

    private void Update()
    {
        #if UNITY_EDITOR
        if (Input.GetKeyUp(KeyCode.KeypadPlus))
        {
            WinBattle();    
        }
        #endif
    }
    
    private void WinBattle()
    {
        GetReward();
        StartCoroutine(WaitForClick(ResetAndGoBackToMap));
    }

    private void ResetAndGoBackToMap()
    {
        PlayerBattleActions.SetActive(false);
        GameManager.Instance.ReturnToMap();
    }

    private void LoseBattle()
    {
        GameOver();
        GameManager.Instance.RestartGame();
    }

    private void GetReward()
    {
        Debug.Log("Rewarded!");
    }

    private void GameOver()
    {
        
    }

    public void ShowMessage(string m, UnityAction callback)
    {
        MessageBoxText.ShowText(m, () => Done());

        void Done()
        {
            Debug.Log("Message presentation done!");
            callback();
        }
    }

    public void SetGrassland()
    {
        Grassland.SetActive(true);
        Snowland.SetActive(false);
        Sandland.SetActive(false);
    }

    public void SetSnowland()
    {
        Grassland.SetActive(false);
        Snowland.SetActive(true);
        Sandland.SetActive(false);
    }

    public void SetSandland()
    {
        Grassland.SetActive(false);
        Snowland.SetActive(false);
        Sandland.SetActive(true);
    }
}
