using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Assets.Scripts.Battle;
using Assets.Scripts.Core;
using Assets.Scripts.Player;
using UnityEngine;
using System.Collections;

namespace Assets.Scripts.UI.Placeholder
{
    class BattleSprite : MonoBehaviour, IMobDisplay
    {
        public GameObject hitAnimation;
        public GameObject noRangePrefab;

        private Mob _mob;
        private SkeletonAnimation _animation;
        private BattleEngine _battle;
        private IBattleUI _battleUI;
        private bool _selected;

        private static BattleSprite _selectionHolder;

        private Bar _cooldownBar;
        private Bar _healthBar;
        private GameObject _noRangeUI;

        public void SetMob(Mob mob, BattleEngine battle, IBattleUI battleUI, SkeletonAnimation animation) {
            if (mob == null) {
                throw new Exception("Mob can't be null");
            }
            _mob = mob;
            _battle = battle;
            _battleUI = battleUI;
            _mob.GraphicalListener = this;
            _animation = animation;
            _animation.state.SetAnimation(1, "Idle", true);
            if (_mob.Flipped) _animation.skeleton.flipX = true;
        }

        protected void OnDestroy() {
            if (_selectionHolder == this) {
                _selectionHolder = null;
            }
            if (_cooldownBar) {
                Destroy(_cooldownBar.gameObject);
            }
            if (_healthBar) {
                Destroy(_healthBar.gameObject);
            }
            _mob.GraphicalListener = null;
        }

        protected void Update() {
            if (_mob.IsAlive()) {
                transform.position = new Vector3(BattleToWorldX(_mob.GetBattlePosition(), _mob.GetAllegiance()), -2.15f, -_mob.BattleIndex / 100);
                UpdateBarPosition(_healthBar, new Vector2(0, 290));
                UpdateBarPosition(_cooldownBar, new Vector3(0, 380));
            }

            if (_selected) {
                var worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                var x = WorldToBattleX(worldPos.x,_mob.GetAllegiance());
                var mobX = _mob.GetBattlePosition();
                int delta = (int)(x - mobX);
                int moveTo = (int) (_mob.GetBattlePosition() + delta);
                int curPos = (int) _mob.GetBattlePosition();

                if (Input.GetMouseButton(0)) {
                    _battleUI.SetMoveCursor(_mob, curPos, moveTo);
                } else {
                    _battleUI.SetMoveCursor(_mob, curPos, curPos);
                    _selected = false;
                    _selectionHolder = null;
                    if (delta != 0) {
                        _battle.MoveCharacter(_mob, moveTo);
                    }
                }
            }
            _healthBar.SetValue(_mob.GetHealthPercent(),false);
            _cooldownBar.SetValue(_mob.GetCooldownPercent(),true);
        }

        public static float BattleToWorldX (float battleX, Allegiance side) {
            return battleX * 2f + 1.8f + GetSideOffset(side);
        }

        public static float WorldToBattleX(float worldX, Allegiance side)
        {
            return (worldX - 1.8f - GetSideOffset(side)) / 2f;
        }

        private static float GetSideOffset(Allegiance side)
        {
            return side == Allegiance.FRIENDLY ? -1 : 1;
        }

        public void Attack() {
            StartCoroutine(PlayAttackAnimation());
        }
        private IEnumerator PlayAttackAnimation()
        {
            _animation.Reset();
            _animation.state.SetAnimation(1, "Attack", false);
            _animation.state.AddAnimation(1, "Idle", true,0);
            yield return 0;
        }

        public void Die() {
            Destroy(gameObject);
        }

        public void TakeHit() {
            Instantiate(hitAnimation, transform.position + new Vector3(0,1.5f,-5), Quaternion.identity);
        }

        public void SetMoving(bool moving) {
            
        }

        public void Miss() {
            
        }

        protected void OnMouseDown () {
            if (_selectionHolder == null && _mob.GetAllegiance() == Allegiance.FRIENDLY) {
                _selected = true;
                _selectionHolder = this;
            }
        }

        public void SetCooldownBar(Bar bar) {
            _cooldownBar = bar;
            bar.SetColour(Color.white, Color.white);
        }

        public void SetHealthBar (Bar bar) {
            _healthBar = bar;
            bar.SetColour(Color.red, Color.white);
        }

        private void UpdateBarPosition (Bar bar, Vector2 offset) {
            bar.transform.localPosition = GetScreenPosition(transform, GlobalCanvas.Instance) + new Vector3(offset.x, offset.y, 0);
        }

        public static Vector3 GetScreenPosition (Transform transform, Canvas canvas) {
            Vector3 pos;
            float width = canvas.GetComponent<RectTransform>().sizeDelta.x;
            float height = canvas.GetComponent<RectTransform>().sizeDelta.y;
            float x = Camera.main.WorldToScreenPoint(transform.position).x / Screen.width;
            float y = Camera.main.WorldToScreenPoint(transform.position).y / Screen.height;
            pos = new Vector3(width * x - width / 2, y * height - height / 2);
            return pos;
        }


        public void ShowNoRange()
        {
            if (_noRangeUI==null)
            {
                _noRangeUI = Instantiate(noRangePrefab, transform.position + new Vector3(0,4.98f,0.02f),Quaternion.identity) as GameObject;
                _noRangeUI.GetComponent<SkeletonAnimation>().state.SetAnimation(1, "Show", false);
                _noRangeUI.transform.parent = transform;
            }
        }

        public void HideNoRange()
        {
            if (_noRangeUI!=null)
            {
                var anim =_noRangeUI.GetComponent<SkeletonAnimation>().state;
                anim.SetAnimation(1, "Hide", false).Complete += (Spine.AnimationState state, int index, int loopCount) => { Destroy(_noRangeUI); };
                _noRangeUI = null;
            }
        }
    }
}
