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

public class TurnManager : MonoBehaviour {

    const float ACTION_ANIM_TIME = GuiStatusText.ATTACK_TIME;
    const float MOVE_DELAY = 0.05f;

    public float m_actionAnimTimeLeft;

    public static TurnManager ms_instance;
    public static TurnManager Instance
    {
        get { return ms_instance; }
    }

    public List<BaseTurn> m_pendingTurns;

    private State m_currentState;
    private MenuAction m_currentAction;

    private GridCoord m_moveToPos;
    private GridCoord m_actionDestPos;

    private int m_chosenMagic = -1;
    private int m_chosenItem = -1;

    public State CurrentState
    {
        get { return m_currentState;  }
    }

    public enum State
    {
        ShowMoveRadius,
        MakeMoveChoice,
        MoveAnimation,
        MakeActionChoice,
        ShowActionRadius,
        MakeMagicChoice,
        MakeItemChoice,
        ChooseActionLocation,
        ConfirmingLocation,     // May just push this into PlayerTurn
        ActionAnim,
        LevelUp,
        TurnDone
    }


    // Use this for initialization
    void Start()
    {
        if (ms_instance != null)
        {
            Debug.LogError("Only one turnman allowed");
        }
        ms_instance = this;

        m_pendingTurns = new List<BaseTurn>();
    }

    public bool TurnFinished()
    {
        return m_pendingTurns.Count == 0;
    }

    public void SetupNewPlayerTurn()
    {
        m_pendingTurns.Clear();

        m_pendingTurns.Add(new PlayerTurn(PlayerObject.Instance));

        StartTurn();
    }

    public bool SetupNewEnemyTurn()
    {
        m_pendingTurns.Clear();

        foreach ( Transform enemy in EnemyManager.Instance.m_enemies )
        {
            m_pendingTurns.Add(new EnemyTurn( enemy.GetComponent<EnemyObject>()));
        }

        StartTurn();

        return m_pendingTurns.Count > 0;
    }

    public void StartTurn()
    {
        // Fist state
        m_currentState = (State)0;

        // Process happens in update
        CharacterStatsGui.ClearEnemy();
    }
    
    void Update()
    {
        if ( TurnFinished() )
        {
            return;
        }

        BaseTurn turn = m_pendingTurns[0];
        Transform objTrans = turn.Transform;

        switch ( m_currentState )
        {
            case State.ShowMoveRadius:
                {
                    SFXManager.Play(SFXManager.Instance.m_bassChange);
                    turn.ShowMoveHighlight();
                    m_currentState = State.MakeMoveChoice;

                    if ( turn.PlayerTurn )
                    {
                        GuiStatusText.DisplayText("Click in the shaded area to move\nClick on Milo to perform actions", GuiStatusText.DEFAULT_TIME);
                    }

                    turn.StartMoveLocPick();
                }
                break;
            case State.MakeMoveChoice:
                {
                    if ( turn.PlayerWantsActionMenu() )
                    {
                        RangeHighlighter.ClearHighlights();
                        m_currentState = State.MakeActionChoice;
                    }
                    else if ( turn.DoMoveChoice( out m_moveToPos ) )
                    {
                        m_currentState = State.MoveAnimation;
                        m_actionAnimTimeLeft = MOVE_DELAY;
                    }
                }
                break;
            case State.MoveAnimation:
                {
                    // TODO - Pathfind and move square-by-square to the dest. Guaranteed to get there by the highlight grid squares
                    // Going crude for now. This one is near the back of the list. Want something
                    
                    GridCoord curPos = objTrans.GetComponent<GridObject>().GridPosition;

                    if ( m_actionAnimTimeLeft > 0.0f )
                    {
                        m_actionAnimTimeLeft -= Time.deltaTime;
                    }
                    else
                    {
                        if (curPos == m_moveToPos)
                        {
                            m_currentState = State.MakeMoveChoice;

                            // Something to tell the AI it's done moving, and can do an action now. Player UI is locked out during the move.
                            turn.HasMoved();
                        }
                        else
                        {
                            m_actionAnimTimeLeft = MOVE_DELAY;
                            int xDelta = (curPos.x - m_moveToPos.x);
                            int yDelta = (curPos.y - m_moveToPos.y);

                            if (Mathf.Abs(xDelta) > Mathf.Abs(yDelta))
                            {
                                if (curPos.x < m_moveToPos.x)
                                {
                                    curPos.x++;
                                }
                                else
                                {
                                    curPos.x--;
                                }
                            }
                            else
                            {
                                if (curPos.y < m_moveToPos.y)
                                {
                                    curPos.y++;
                                }
                                else
                                {
                                    curPos.y--;
                                }
                            }
                            objTrans.GetComponent<GridObject>().UpdatePosition(curPos, false);
                            CameraPan.Instance.MoveToPos(curPos, true);
                        }
                    }


                }
                break;
            case State.MakeActionChoice:
                {
                    MenuAction action;
                    if ( turn.MadeMenuChoiceMove( out action ) )
                    {
                        ProcessActionChoice(action, turn);
                    }
                }
                break;
            case State.MakeMagicChoice:
                {
                    if (turn.MadeMagicChoice(out m_chosenMagic))
                    {
                        if (m_chosenMagic >= 0)
                        {
                            MagicID magicId = objTrans.GetComponent<CharacterObject>().Info.m_magic[m_chosenMagic];
                            if ( CharacterMagic.GetMagic(magicId).m_offensive )
                            {
                                m_currentState = State.ShowActionRadius;
                            }
                            else
                            {
                                // Just go into the action for healing
                                turn.ForcePlayerOnPlayerAction(); //< The AOE hack isn't being used to catch targets, so force it to the player itself
                                m_currentState = State.ActionAnim;
                            }
                        }
                        else
                        {
                            // Cancel. Go back to initial state to show move highlights again.
                            m_currentState = State.ShowMoveRadius;
                        }
                    }
                }
                break;
            case State.MakeItemChoice:
                {
                    if (turn.MadeItemChoice(out m_chosenItem))
                    {
                        if (m_chosenItem >= 0)
                        {
                            // Just go into the action for items... Only healing items supported by the player. 
                            turn.ForcePlayerOnPlayerAction(); //< The AOE hack isn't being used to catch targets, so force it to the player itself
                            m_currentState = State.ActionAnim;
                        }
                        else
                        {
                            // Cancel. Go back to initial state to show move highlights again.
                            m_currentState = State.ShowMoveRadius;
                        }
                    }
                }
                break;
            case State.ShowActionRadius:
                {
                    SFXManager.Play(SFXManager.Instance.m_bassChange);
                    turn.ShowActionRadiusHighlight( m_currentAction, m_chosenMagic );
                    turn.StartActionLocPick();
                    m_currentState = State.ChooseActionLocation;

                    if ( turn.PlayerTurn )
                    {
                        // Extra tip to show bow vs sword attack scores
                        string tip = "";

                        CharacterInfo charInfo = PlayerObject.Instance.Info;

                        if ( charInfo.MeleeWeapon != null )
                        {
                            tip += string.Format("{0} ATK:{1}\n", charInfo.MeleeWeapon.m_name, charInfo.MeleeWeapon.m_attackBuff + charInfo.m_attack);
                        }
                        if (charInfo.RangedWeapon != null)
                        {
                            tip += string.Format("{0} ATK:{1}\n", charInfo.RangedWeapon.m_name, charInfo.RangedWeapon.m_attackBuff + charInfo.m_attack);
                        }

                        if ( tip.Length > 0 )
                        {
                            GuiStatusText.DisplayText(tip, GuiStatusText.DEFAULT_TIME );
                        }
                    }
                }
                break;
            case State.ChooseActionLocation:
                {
                    bool cancel;
                    if (turn.DoActionLocationPick(out m_actionDestPos, out cancel))
                    {
                        RangeHighlighter.ClearHighlights();
                        if ( cancel )
                        {
                            m_currentState = State.ShowMoveRadius;
                        }
                        else
                        {
                            m_currentState = State.ConfirmingLocation;
                            SFXManager.Play(SFXManager.Instance.m_bassChange);
                            turn.ShowAOEHighlight(m_currentAction, m_actionDestPos, m_chosenMagic);
                        }
                    }
                }
                break;
            case State.ConfirmingLocation: // May just push this into PlayerTurn
                {
                    MenuAction action;
                    if (turn.MadeMenuChoiceAction(out action))
                    {
                        ProcessConfirmChoice(action);
                    }
                }
                break;
            case State.ActionAnim:
                {
                    // TODO: Effects

                    UpdateActionAnims();

                    if ( m_newvictim )
                    {
                        m_newvictim = false;
                        if (turn.PerformActions(m_currentAction, out m_lastVictim, m_chosenMagic, m_chosenItem))
                        {
                            // Done
                            m_lastVictim = null;
                            EndActionAnims();
                            
                            if ( turn.PlayerTurn )
                            {
                                //Debug.Log("Exp" + PlayerObject.Instance.Info.m_experience);
                                if (PlayerObject.Instance.Info.m_experience < CharacterInfo.EXP_FOR_LEVEL_GAIN)
                                {
                                    m_currentState = State.TurnDone;
                                }
                                else
                                {
                                    //Debug.Log("Level Up1");
                                    m_actionAnimTimeLeft = PlayerObject.Instance.LevelUp();
                                    m_currentState = State.LevelUp;
                                }
                            }
                            else
                            {
                                m_currentState = State.TurnDone;
                            }
                        }
                        else
                        {
                            // Another wait for the next AOE victim
                            m_actionAnimTimeLeft = ACTION_ANIM_TIME;
                        }
                    }

                    m_actionAnimTimeLeft -= Time.deltaTime;
                    if ( GuiStatusText.CanContinue )
                    {
                        PotentiallyKillLastVictim();
                        m_newvictim = true;
                    }
                }
                break;

            case State.LevelUp:
                {
                    //Debug.Log("Level Up2");
                    m_actionAnimTimeLeft -= Time.deltaTime;
                    if (GuiStatusText.CanContinue)
                    {
                        m_currentState = State.TurnDone;
                    }
                }
                break;

            case State.TurnDone:
                {
                    m_pendingTurns.RemoveAt(0);
                    m_currentState = (State)0;

                    if ( PlayerObject.Instance.Info.IsDead )
                    {
                        m_pendingTurns.Clear();
                    }
                    //Debug.Log("Turn Done " + m_pendingTurns.Count + " left");
                }
                break;
        }
    }

    private CharacterObject m_lastVictim;
    private bool m_newvictim = false;

    public void StartActionAnim(MenuAction action)
    {
        m_currentState = State.ActionAnim;

        if (action == MenuAction.Stay)
        {
            m_actionAnimTimeLeft = 0.0f;
        }
        else
        {
            m_newvictim = true;
            m_actionAnimTimeLeft = ACTION_ANIM_TIME;
        }
    }

    public void UpdateActionAnims()
    {

    }

    public void EndActionAnims()
    {

    }

    public void PotentiallyKillLastVictim()
    {
        if (m_lastVictim == null)
        {
            return;
        }
        if (m_lastVictim.Info.IsDead == false )
        {
            return;
        }

        SFXManager.PlayDeath();

        if ( m_lastVictim.IsPlayer )
        {
            // Oh dear! Milo is dead
        }
        else
        {
            // TODO : SFX
            EnemyManager.Instance.KillEnemy(m_lastVictim.GetComponent<EnemyObject>());
        }
    }


    public void ProcessActionChoice( MenuAction action, BaseTurn turn )
    {
        switch ( action )
        {
            case MenuAction.Stay:
                {
                    StartActionAnim(action);
                }
                break;

            case MenuAction.Attack:
                {
                    m_currentAction = action;
                    m_currentState = State.ShowActionRadius;
                }
                break;

            case MenuAction.Magic:
                {
                    turn.ShowMagicChoiceMenu();
                    m_currentAction = action;
                    m_currentState = State.MakeMagicChoice;
                }
                break;

            case MenuAction.Item:
                {
                    turn.ShowItemChoiceMenu();
                    m_currentAction = action;
                    m_currentState = State.MakeItemChoice;
                }
                break;
                
            default:
                {
                    // Cancel. Go back to initial state to show move highlights again.
                    m_currentState = State.ShowMoveRadius;
                }
                break;
        }
    }

    public void ProcessConfirmChoice(MenuAction action )
    {
        switch (action)
        {
            case MenuAction.Confirm:
                {
                    StartActionAnim(m_currentAction);
                }
                break;
                
            default:
                {
                    // Cancel. Go back to initial state to show move highlights again.
                    m_currentState = State.ShowMoveRadius;
                }
                break;
        }
    }


}
