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

public abstract class BaseTurn
{
    public BaseTurn(CharacterObject obj)
    {
        m_charObject = obj;
        m_startPosition = m_charObject.GetComponent<GridObject>().GridPosition;
    }

    protected CharacterObject m_charObject;
    protected GridCoord m_startPosition;
    protected bool m_filterToEnemies;
    protected List<CharacterObject> m_lastAoeMatches;
    protected bool m_offensive;



    public Transform Transform
    {
        get { return m_charObject.transform;  }
    }

    static public bool IsOffensiveAction( MenuAction action )
    {
        return true;
    }

    public void ShowMoveHighlight()
    {
        m_lastAoeMatches = null;

        m_charObject.GetComponent<RangeHighlighter>().ShowMoveHighlight(m_startPosition, m_charObject.Info.Movement);
        CameraPan.Instance.MoveToPos(m_startPosition, true);
    }

    public bool PlayerTurn
    {
        get { return (m_charObject == PlayerObject.Instance.GetComponent<CharacterObject>()); }
    }

    public void ShowActionRadiusHighlight(MenuAction action, int magicIndex)
    {
        bool allowMelee = true;
        int maxRange = 1;
        m_offensive = true;

        switch (action)
        {
            case MenuAction.Attack:
                {
                    if (m_charObject.Info.CanMeleeAttack == false)
                    {
                        allowMelee = false;
                    }
                    if (m_charObject.Info.CanRangedAttack )
                    {
                        maxRange = m_charObject.Info.RangedWeapon.m_weaponMaxRange;
                    }
                }
                break;

            case MenuAction.Magic:
                {
                    MagicID magicId = m_charObject.Info.m_magic[magicIndex];
                    maxRange = CharacterMagic.GetMagic(magicId).m_range;
                }
                break;

            case MenuAction.Item:
                {
                    // No offensive items. Just have it skip this
                }
                break;
        }

        m_filterToEnemies = m_offensive;
        if (PlayerTurn == false)
        {
            // Enemies turn, they want the reverse
            m_filterToEnemies = !m_filterToEnemies;
        }

        m_charObject.GetComponent<RangeHighlighter>().ShowActionHighlight(allowMelee, maxRange, (MenuAction.Attack == action));
        m_charObject.GetComponent<RangeHighlighter>().SetCanBeSelectedByAction(m_filterToEnemies);
        CameraPan.Instance.MoveToPos(m_charObject.GetComponent<GridObject>().GridPosition, true);
    }

    public void ShowAOEHighlight(MenuAction action, GridCoord targetPos, int magicIndex)
    {
        int aoeSize = 1;

        if ( m_offensive )
        {
            if ( PlayerTurn )
            {
                GridObject targetObj;
                if ( GridManager.Instance.TestCollision( targetPos, out targetObj, false ) )
                {
                    CharacterStatsGui.SetEnemy(targetObj.transform);
                }
            }
        }

        switch (action)
        {
            case MenuAction.Attack:
                {
                    // Always just one
                }
                break;

            case MenuAction.Magic:
                {
                    MagicID magicId = m_charObject.Info.m_magic[magicIndex];
                    aoeSize = CharacterMagic.GetMagic(magicId).m_aoe;
                }
                break;

            case MenuAction.Item:
                {
                    // Always just one. Well, we'll never get here, actually.
                }
                break;
        }

        m_charObject.GetComponent<RangeHighlighter>().ShowAOEHighlight(targetPos, aoeSize);
        m_charObject.GetComponent<RangeHighlighter>().SetCanBeSelectedByAction(m_filterToEnemies);
        m_lastAoeMatches = m_charObject.GetComponent<RangeHighlighter>().GetAffectedAOE();
    }

    public void ForcePlayerOnPlayerAction()
    {
        // Agh. Why didn't I just make this list always exist, and empty it!
        m_lastAoeMatches = new List<CharacterObject>();
        m_lastAoeMatches.Add(PlayerObject.Instance.GetComponent<CharacterObject>());
        m_offensive = false; // Whee! Perfect place to fix that.
    }

    public bool PerformActions( MenuAction action, out CharacterObject hitObject, int magicIndex, int itemIndex )
    {
        // returns true when done

        hitObject = null;

        GridObject gridObj = m_charObject.GetComponent<GridObject>();
        CharacterObject attacker = gridObj.GetComponent<CharacterObject>();

        // Commit move
        gridObj.UpdatePosition(gridObj.GridPosition, true);

        if (m_lastAoeMatches != null) 
        {
            if (m_lastAoeMatches.Count > 0)
            {
                // Pop off front
                CharacterObject charObj = m_lastAoeMatches[0];
                m_lastAoeMatches.RemoveAt(0);

                hitObject = charObj;


                //Debug.Log("Hit " + m_lastAoeMatches.Count + " characters");
                {
                    if (m_offensive)
                    {
                        switch (action)
                        {
                            case MenuAction.Attack:
                                {
                                    // Only ever one victim of an attack
                                    BattleCalculator.ProcessAttack(attacker.Info, charObj.Info, IsAttackMelee(attacker.GridPosition, charObj.GridPosition));
                                }
                                break;
                            case MenuAction.Magic:
                                {
                                    // Magic may have multiple victims
                                    MagicID magicId = attacker.Info.m_magic[magicIndex];
                                    BattleCalculator.ProcessMagicAttack(attacker.Info, charObj.Info, magicId, m_lastAoeMatches.Count == 0 );
                                }
                                break;
                            case MenuAction.Item:
                                {
                                    // TODO: Prob not doing offensive items
                                    Debug.LogError("AttackItem!");
                                }
                                break;
                        }
                    }
                    else
                    {
                        switch (action)
                        {
                            case MenuAction.Attack:
                                {
                                    // No healing attacks
                                }
                                break;
                            case MenuAction.Magic:
                                {
                                    SFXManager.Play(SFXManager.Instance.m_magicHeal);

                                    MagicID magicId = attacker.Info.m_magic[magicIndex];
                                    BattleCalculator.ProcessHealing(attacker.Info, charObj.Info, magicId);
                                }
                                break;
                            case MenuAction.Item:
                                {
                                    SFXManager.Play(SFXManager.Instance.m_healItem);

                                    BattleCalculator.ProcessHealing(attacker.Info, charObj.Info, itemIndex);
                                }
                                break;
                        }
                    }
                }

                if (m_lastAoeMatches.Count == 0)
                {
                    if ( attacker.IsPlayer )
                    {
                        attacker.Info.m_pendingXP = Mathf.Max(1, attacker.Info.m_pendingXP);
                        attacker.Info.m_pendingXP = Mathf.Min(attacker.Info.m_pendingXP, BattleCalculator.MAX_XP_TURN);

                        //attacker.Info.m_pendingXP = 100;

                        if (attacker.Info.m_pendingXP > 0)
                        {
                            GuiStatusText.AppendText( string.Format("\n{0} gained {1} XP", attacker.Info.m_name, attacker.Info.m_pendingXP));
                        }

                        if (attacker.Info.m_pendingGold > 0)
                        {
                            GuiStatusText.AppendText(string.Format("\n{0} gained {1} Gold", attacker.Info.m_name, attacker.Info.m_pendingGold));
                        }

                        attacker.Info.AwardXPAndGold();
                    }
                }

                return false;
            }
        }

        return true;
    }

    static public bool IsAttackMelee(GridCoord one, GridCoord two)
    {
        // NOTE: There are no hybrid attacking items. It's either melee only, or ranged only.

        if (new GridCoord(one.x, one.y + 1) == two)
        {
            return true;
        }
        if (new GridCoord(one.x, one.y - 1) == two)
        {
            return true;
        }
        if (new GridCoord(one.x + 1, one.y) == two)
        {
            return true;
        }
        if (new GridCoord(one.x - 1, one.y) == two)
        {
            return true;
        }

        return false;
    }

    public abstract void StartMoveLocPick();

    public abstract bool DoMoveChoice(out GridCoord destPos);

    public abstract bool PlayerWantsActionMenu();

    public abstract void HasMoved();

    public abstract bool MadeMenuChoiceMove(out MenuAction choice);

    public abstract void ShowMagicChoiceMenu();
    public abstract void ShowItemChoiceMenu();

    public abstract bool MadeMagicChoice(out int choiceIndex);
    public abstract bool MadeItemChoice(out int choiceIndex);

    public abstract void StartActionLocPick();

    public abstract bool DoActionLocationPick(out GridCoord targetPos, out bool cancel);

    public abstract bool MadeMenuChoiceAction(out MenuAction choice);


}

