using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum ChoreographerStates
{
    Initialization,
    DrawingCards,
    Idle,
    PlayingACard,
    PlayCardCleanup,
    MonsterTurn,
    WaitingForAllMonsterAttacks,
    Cleanup,
}

public class Choreographer : MonoBehaviour
{
    public ChoreographerStates CurrentState;

    public GameObject PlayerEntity = null;

    public CardInstance CardToPlay = null;
    private float CardPlayTime = 0.5f;
    private float TimeBetweenMonsterTurns = 0.5f;
    public float TimeToStateEvent = 0.0f;

    public void PlayCard(CardInstance card)
    {
        if (CardToPlay == null)
        {
            CardToPlay = card;
            CurrentState = ChoreographerStates.PlayingACard;
            TimeToStateEvent = Time.time + CardPlayTime;

            // Charge the mana immediately
            EnergyComponent playerEnergy = PlayerEntity.GetComponent<EnergyComponent>();
            playerEnergy.AddEnergy(-CardToPlay.CardTemplate.ManaCost);

            // Move the played card up
            GetComponent<CardManager>().PlayCard(card);

            // Move the other cards to the discard pile
            GetComponent<CardManager>().DiscardAllBut(CardToPlay);

        }
    }

    // Start is called before the first frame update
    void Start()
    {
        CurrentState = ChoreographerStates.Initialization;
    }

    List<SwingTimerComponent> pendingSwingers = new List<SwingTimerComponent>();


    bool SettingUpGame = false;
    private IEnumerator SetupGame()
    {
        PlayerEntity.GetComponent<HealthComponent>().MaxHealth = PlayerStats.MaxHealth;
        PlayerEntity.GetComponent<HealthComponent>().Health = PlayerEntity.GetComponent<HealthComponent>().MaxHealth;
        PlayerEntity.GetComponent<EnergyComponent>().MaxEnergy = PlayerStats.MaxEnergy;
        PlayerEntity.GetComponent<EnergyComponent>().Energy = 0;
        foreach(string cardname in PlayerStats.Deck)
        {
            GetComponent<CardManager>().AddCardToDeck(GetComponent<CardFactory>().CreateCard(CardDatabase.Instance.FindCardByName(cardname)));
            yield return new WaitForSeconds(0.1f);
        }

        // Spawn Monsters
        GetComponent<ScenarioManager>().SpawnScenario(PlayerStats.Level);

        yield return new WaitForSeconds(0.5f);
        // Let the game begin
        SettingUpGame = false;
        CurrentState = ChoreographerStates.DrawingCards;
    }

    bool DrawingToFull = false;
    private IEnumerator DrawToFull()
    {
        // Grant energy for starting the round
        PlayerEntity.GetComponent<EnergyComponent>().AddEnergy(1);

        // Then draw cards
        CardManager cm = GetComponent<CardManager>();

        while (cm.Hand.Count < cm.MaxHandSize && (cm.Deck.Count + cm.Discard.Count) > 0)
        {
            if (cm.Deck.Count == 0)
            {
                GetComponent<StatusText>().ShowMessage("Shuffling...");

                cm.ReturnDiscardToDeck();
                yield return new WaitForSeconds(0.75f);
                GetComponent<StatusText>().ShowMessage("");
            }

            cm.DrawTopCardToHand();
            yield return new WaitForSeconds(0.25f);
        }

        DrawingToFull = false;
        GetComponent<StatusText>().ShowMessage("Choose a card");
        CurrentState = ChoreographerStates.Idle;
    }

    // Update is called once per frame
    void Update()
    {
        if (CurrentState == ChoreographerStates.Initialization)
        {
            if (!SettingUpGame)
            {
                SettingUpGame = true;
                StartCoroutine("SetupGame");
            }
        }
        else if (CurrentState == ChoreographerStates.DrawingCards)
        {
            if (!DrawingToFull)
            {
                DrawingToFull = true;
                StartCoroutine("DrawToFull");
            }

        }
        else if (CurrentState == ChoreographerStates.PlayingACard)
        {
            GetComponent<StatusText>().ShowMessage("");
            if (Time.time > TimeToStateEvent)
            {
                GetComponent<CardDispatcher>().ExecuteCardAction(CardToPlay.CardTemplate, GetComponent<GodHand>().GetCurrentTarget());


                // Return card to discard pile
                GetComponent<CardManager>().DiscardCard(CardToPlay);

                CardToPlay = null;

                // After I play a card, the monsters take their turn
                CurrentState = ChoreographerStates.PlayCardCleanup;

                TimeToStateEvent = Time.time + 0.5f;
            }
        }
        else if (CurrentState == ChoreographerStates.PlayCardCleanup)
        {
            if (Time.time > TimeToStateEvent)
            {
                // Queue up all available attacking monsters here
                pendingSwingers.AddRange(FindObjectsOfType<SwingTimerComponent>());

                TimeToStateEvent = Time.time + TimeBetweenMonsterTurns;
                CurrentState = ChoreographerStates.MonsterTurn;
            }
        }
        else if (CurrentState == ChoreographerStates.MonsterTurn)
        {
            if (Time.time > TimeToStateEvent)
            {
                bool monsterSwung = false;
                if (pendingSwingers.Count > 0)
                {
                    // Remove one
                    SwingTimerComponent stc = pendingSwingers[pendingSwingers.Count - 1];
                    pendingSwingers.RemoveAt(pendingSwingers.Count - 1);

                    // Perform it's swing actions
                    stc.TurnsRemaining--;
                    stc.DirtyUI = true;

                    if (stc.TurnsRemaining <= 0)
                    {
                        stc.GetComponent<Animator>().SetTrigger("Attack");
                        monsterSwung = true;

                        // Perform damage here
                        stc.ContactFrameReached += MonsterSwingingContactFrame;
                    }
                }

                // Set up either the next monster turn or advance to player idle
                if (pendingSwingers.Count > 0)
                {
                    TimeToStateEvent = Time.time + TimeBetweenMonsterTurns;
                }
                else
                {
                    CurrentState = ChoreographerStates.WaitingForAllMonsterAttacks;
                }

                if (monsterSwung)
                    TimeToStateEvent = Time.time + 1.0f + TimeBetweenMonsterTurns;

            }
        }
        else if (CurrentState == ChoreographerStates.WaitingForAllMonsterAttacks)
        {
            if (Time.time > TimeToStateEvent)
                CurrentState = ChoreographerStates.Cleanup;

        }
        else if (CurrentState == ChoreographerStates.Cleanup)
        {
            // Check for player victory
            if (FindObjectsOfType<SwingTimerComponent>().Length == 0)
            {
                // All monsters are dead
                UnityEngine.SceneManagement.SceneManager.LoadScene("HealScreen");
            }

            // Check for monster victory
            if (PlayerEntity.GetComponent<HealthComponent>().Health <= 0.0f)
            {
                // Player Died
                UnityEngine.SceneManagement.SceneManager.LoadScene("LoseScreen");

            }
            PlayerEntity.GetComponent<HealthComponent>().BarkskinActive = false;

            CurrentState = ChoreographerStates.DrawingCards;
        }



    }

    private void MonsterSwingingContactFrame(object sender, System.EventArgs e)
    {
        SwingTimerComponent stc = (sender as SwingTimerComponent);
        PlayerEntity.GetComponent<HealthComponent>().PendingDamage += stc.GetComponent<MonsterStats>().Damage;
        stc.TurnsRemaining = stc.ChargingTurns;
        stc.DirtyUI = true;
        stc.ContactFrameReached -= MonsterSwingingContactFrame;
    }

    public void PlayerPasses()
    {
        // You can only pass while it's your turn (idle)
        if (CurrentState == ChoreographerStates.Idle)
        {
            GetComponent<CardManager>().DiscardAll();

            // After I play a card, the monsters take their turn
            CurrentState = ChoreographerStates.PlayCardCleanup;

            TimeToStateEvent = Time.time + 0.5f;

        }
    }
}
