using System.Collections.Generic;
using System.Linq;
using Assets.Source.Constants;
using Assets.Source.Content.UI.Topdown;
using Assets.Source.Core.Managers;
using Assets.Source.Misc;
using Assets.Source.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Assets.Source.Core.Gameplay.Topdown
{
    public class PlayerShipTopdown : MonoDestroyTracker, IDamageable, IDamager
    {
        public Transform Turret;
        public Canvas UICanvas;
        public RectTransform UIDangerWarning;
        public UIDestinationArrow UIDestinationArrow;
        public Animator UiDangerWarningAnimator;

        [Header("Movement")]
        public float MovementSpeed = 1;
        public float MovementAccelerationLerp = 1;
        public float RotationSpeed = 1;
        public float BoundsForce = 1;

        [Header("Shooting")]
        public float TurretAimingSpeed = 1;
        public float ShootingCooldown = 0.2f;
        public float BulletInertiaFactor = 1;
        public float DispersionAngle = 15;

        [Header("General")]
        public int MaxHealth = 3;

        private Vector2 _inputMovement;
        private bool _boundsDanger;
        private float _shootingCooldownValue = 1;
        private float _takingDamageCooldownProgress;

        public Vector2 CurrentMovement { get; private set; }

        public int CurrentHealth;

        public AlienInfo SeatAlienInfo;
        public AlienTopdown SeatAlien;

        void Awake()
        {
            UIDangerWarning.gameObject.SetActive(false);
            CurrentHealth = 6;
        }

        void Start()
        {
            SetNextDestination();
        }

        public void SetNextDestination(Transform target = null)
        {
            if (target != null)
            {
                UIDestinationArrow.Target = target;
                return;
            }

            Transform targetTransform = null;
            if (SeatAlienInfo != null)
            {
                targetTransform = GameManagerTopdown.Instance.WorldMap.Planets.FirstOrDefault(planet => planet.OriginInfo == SeatAlienInfo)?.transform;
            }
            else
            {
                var t = GameManagerTopdown.Instance.WorldMap.Aliens.OrderBy(a => a.transform.position.DistTo(transform.position)).FirstOrDefault();
                targetTransform = t?.transform;
            }
            UIDestinationArrow.Target = targetTransform;
        }

        void Update()
        {
            if (GameManagerTopdown.Instance.SolvingPlanet || !GameManagerTopdown.Instance.InputEnabled)
                return;

            _inputMovement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
            _inputMovement = Vector2.ClampMagnitude(_inputMovement, 1);

            var clickPos = Input.mousePosition;
            Vector2 originPoint = CameraTopdown.Instance.Camera.ScreenPointToRay(clickPos).origin;

            var results = new List<RaycastResult>();
            var pointer = new PointerEventData(EventSystem.current) { position = clickPos };
            EventSystem.current.RaycastAll(pointer, results);
            var canInput = results.All(result => result.gameObject.GetComponent<Image>() == null) &&
                               !Get.MainUI.DialogueLayer.BlockerActive;
            if (!canInput)
                return;

            if (Input.GetMouseButton(0))
                Shoot();
        }

        void FixedUpdate()
        {
            UpdateMovement();
            UpdateTurret();

            if (_shootingCooldownValue < 1)
                _shootingCooldownValue += Time.fixedDeltaTime / ShootingCooldown;

            _takingDamageCooldownProgress += Time.fixedDeltaTime;
        }

        private void UpdateTurret()
        {
            var mousePos = CameraTopdown.Instance.Camera.ScreenToWorldPoint(Input.mousePosition);
            var dir = mousePos - Turret.position;
            Turret.transform.rotation = Quaternion.Lerp(Turret.transform.rotation, dir.DirToRotation(),
                Time.fixedDeltaTime * TurretAimingSpeed);
        }

        public void Shoot()
        {
            if (_shootingCooldownValue < 1)
                return;
            _shootingCooldownValue = 0;
            var r = Turret.rotation.eulerAngles;
            var bullet = Get.CommonPrefabs.TopdownPrefabs.Bullet.Spawn(Turret.position + Turret.right * 0.3f);
            bullet.After(3f, () => bullet.Release());
            r.z += Random.Range(-DispersionAngle, DispersionAngle);
            //bullet.Speed += _inputMovement * 5;
            bullet.ExtraVelocity += _inputMovement * BulletInertiaFactor;
            bullet.transform.rotation = Quaternion.Euler(r);
            AudioManager.Instance.PlayShipShoot();
            //CameraTopdown.Instance.ShakePos(Get.Animations.Topdown.CamShakePlayerShoot);
        }

        private void UpdateMovement()
        {
            AudioManager.Instance.UpdateShipEngineVolume(_inputMovement.magnitude);
            // Input movement
            CurrentMovement = Vector2.Lerp(CurrentMovement, _inputMovement, Time.fixedDeltaTime * MovementAccelerationLerp);
            transform.position += (Vector3) CurrentMovement * Time.fixedDeltaTime * MovementSpeed;
            if (CurrentMovement.magnitude > 0)
            {
                var dir = CurrentMovement;
                var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
                transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.AngleAxis(angle, Vector3.forward),
                    Time.fixedDeltaTime * RotationSpeed);
            }

            // Bounds pushback
            var bounds = GameManagerTopdown.Instance.Bounds;
            if (!bounds.bounds.Contains(transform.position))
            {
                var closest = bounds.bounds.ClosestPoint(transform.position);
                var dir = closest - transform.position;
                var mult = dir.magnitude + 0.1f;
                transform.position += dir * mult * BoundsForce * Time.fixedDeltaTime;
                //if (!_boundsDanger)
                //    SetDangerWarning(true);
                //_boundsDanger = true;
            }
            else
            {
                //if (_boundsDanger)
                //    SetDangerWarning(false);
                //_boundsDanger = false;
            }
        }

        private int _dangerWarningStacks;
        public void SetDangerWarning(bool active)
        {
            _dangerWarningStacks += active ? 1 : -1;
            if (active)
                UIDangerWarning.gameObject.SetActiveSafe(true);
            UiDangerWarningAnimator.SetTrigger(_dangerWarningStacks > 0
                ? GeneralConstants.ANIM_PARAM_ACTIVATE
                : GeneralConstants.ANIM_PARAM_DEACTIVATE);
        }

        public void TakeDamage(IDamager damager, int damage)
        {
            var damageDenied = Get.DebugSettings.Invul ||
                _takingDamageCooldownProgress < 1 ||
                GameManagerTopdown.Instance.SolvingPlanet ||
                damager is BulletTopdown ||
                !GameManagerTopdown.Instance.InputEnabled;
            if (damageDenied)
                return;
            _takingDamageCooldownProgress = 0;
            CurrentHealth -= damage;
            if (CurrentHealth < 0)
                CurrentHealth = 0;
            CameraTopdown.Instance.ShakePos(Get.Animations.Topdown.CamShakePlayerHit);
            if (CurrentHealth == 0)
                Get.MainUI.OpenDialogue<UIDefeatDialogue>();
        }

        public void Heal(int amount)
        {
            CurrentHealth += amount;
            if (CurrentHealth > MaxHealth)
                CurrentHealth = MaxHealth;
        }
    }
}