using UnityEngine;
using Saltosion.OneWeapon.Enemies;
using Saltosion.OneWeapon.Effects;
using Saltosion.OneWeapon.Player;

namespace Saltosion.OneWeapon.AI.Behaviours {
    [RequireComponent(typeof(Follow), typeof(Enemy), typeof(Explodable))]
    public class ExplodeFollowed : AIBehaviour {
        public float StartExplodingRadius;
        public float ExplodeOnImpactRadius;
        public float ExplosionRadius;
        public float FuseDuration;
        [Tooltip("The amount of damage when barely in the explosion radius")]
        public float MinDamage;
        [Tooltip("The amount of damage when in impact radius")]
        public float MaxDamage;
        [Header("Graphics")]
        public SpriteRenderer SpriteRenderer;
        public Transform ExplosionAnimationTransform;
        public float ExplosionAnimationDuration;
        public float BlinkingRate;

        private Enemy Enemy;
        private Follow Follow;
        private Explodable Explodable;
        private float OriginalFollowPositionUpdateFrequency;

        private bool Exploding = false;
        private float FuseStartTime;

        private bool ExplosionStarted = false;
        private float ExplosionProgress = 0.0f;

        private void Start() {
            Enemy = GetComponent<Enemy>();
            Follow = GetComponent<Follow>();
            Explodable = GetComponent<Explodable>();
            OriginalFollowPositionUpdateFrequency = Follow.TargetPositionUpdateFrequency;
        }

        public override bool CanBehave() {
            return true;
        }

        public override void Execute() {
            float Distance = Follow.Target != null ? (Follow.Target.position - transform.position).magnitude : float.PositiveInfinity;
            bool ImpactExplode = Distance <= ExplodeOnImpactRadius;
            bool TimeExplode = Exploding && Time.time - FuseStartTime >= FuseDuration;
            if (!ExplosionStarted && (ImpactExplode || TimeExplode)) {
                ExplosionStarted = true;
                CurrentStatus = "BOOM";
            } else if (Distance <= StartExplodingRadius && !Exploding) {
                Exploding = true;
                FuseStartTime = Time.time;
                Follow.SetUpdateFrequency(OriginalFollowPositionUpdateFrequency / 3f);
                CurrentStatus = "CloseEnoughNow";
            } else if (Exploding) {
                CurrentStatus = "Exploding: " + (Time.time - FuseStartTime).ToString("0.0") + " > " + FuseDuration.ToString("0.0");
            } else {
                CurrentStatus = "NotCloseEnough";
            }

            // Animation
            if (ExplosionStarted) {
                if (ExplosionProgress >= 1.0f) {
                    Explode(Distance);
                } else {
                    ExplosionProgress += Time.deltaTime / ExplosionAnimationDuration;
                    float AnimMidpoint = 0.5f;
                    if (ExplosionProgress < AnimMidpoint) {
                        float MinifyProgress = ExplosionProgress / AnimMidpoint;
                        ExplosionAnimationTransform.localScale = new Vector3(1, 1, 1) * (1.0f - MinifyProgress * 0.5f);
                    } else {
                        float ExpansionProgress = (ExplosionProgress - AnimMidpoint) / (1.0f - AnimMidpoint);
                        ExplosionAnimationTransform.localScale = new Vector3(1, 1, 1) * (0.5f + ExpansionProgress);
                    }
                }
            }
            if (Exploding) {
                float Intensity = Mathf.Sin(Time.time * Mathf.PI * 2.0f * BlinkingRate) * 0.5f + 0.5f;
                SpriteRenderer.material.SetFloat("_Intensity", Intensity);
            } else {
                SpriteRenderer.material.SetFloat("_Intensity", 0.0f);
            }
        }

        private void OnDrawGizmosSelected() {
            Gizmos.color = new Color(1.0f, 0.2f, 0.2f, 0.8f);
            Gizmos.DrawWireSphere(transform.position, ExplodeOnImpactRadius);
            Gizmos.color = new Color(1.0f, 0.0f, 0.0f, 1.0f);
            Gizmos.DrawWireSphere(transform.position, ExplosionRadius);
            Gizmos.color = new Color(1.0f, 0.5f, 0.5f, 0.5f);
            Gizmos.DrawWireSphere(transform.position, StartExplodingRadius);
        }

        private void Explode(float distance) {
            Collider2D[] NearbyColliders = Physics2D.OverlapCircleAll(transform.position, ExplosionRadius);
            foreach (Collider2D Collider in NearbyColliders) {
                PlayerFun PlayerFun = Collider.GetComponent<PlayerFun>();
                Health Health = Collider.GetComponent<Health>();
                if (PlayerFun != null) {
                    PlayerFun.TakeExplosionDamage();
                }
                if (Health != null) {
                    float ScaledDistance = Mathf.Clamp((distance - ExplodeOnImpactRadius) / (ExplosionRadius - ExplodeOnImpactRadius), 0, 1);
                    float Damage = MinDamage + (MaxDamage - MinDamage) * (1.0f - ScaledDistance);
                    Vector2 Direction = (Collider.transform.position - transform.position).normalized;
                    Health.Damage(Damage, Direction, false);
                }
            }
            Explodable.Explode(true, false);
        }
    }
}
