using UnityEngine;

namespace eagle {
    /// <summary>
    /// Spawns a small group of animated 2D monsters that wander randomly within a radius.
    /// Each monster independently idles, walks to random points, and occasionally attacks.
    /// Uses the same animator state names as DungeonMonsters2D prefabs (Idle, Move, Attack, etc.).
    /// </summary>
    [RequireComponent(typeof(RectTransform))]
    public class MonsterEffect : MonoBehaviour {
        [Header("Monster Prefabs")]
        [Tooltip("One or more prefabs; each spawned monster picks randomly from this list")]
        public GameObject[] monsterPrefabs;

        [Header("Group Settings")]
        public int monsterCount = 3;
        public float wanderRadius = 25f;
        public float moveSpeed = 15f;
        public float monsterScale = 2f;

        [Header("Behavior Timing")]
        public float minIdleDuration = 1f;
        public float maxIdleDuration = 3f;
        [Tooltip("Chance of performing an attack/special after arriving (0-1)")]
        public float actionChance = 0.3f;

        private enum MonsterStateType { Idle, Walking, Action }

        private class MonsterState {
            public GameObject instance;
            public Animator animator;
            public MonsterStateType state;
            public Vector3 targetPosition;
            public float timer;
            public bool facingRight;
        }

        private MonsterState[] _monsters;

        private static readonly int AttackTrigger = Animator.StringToHash("AttackTrigger");
        private static readonly int SpecialATrigger = Animator.StringToHash("SpecialATrigger");
        private static readonly int MoveStateHash = Animator.StringToHash("Move");
        private static readonly int IdleStateHash = Animator.StringToHash("Idle");

        void Start() { SpawnMonsters(); }

        private void SpawnMonsters() {
            if (monsterPrefabs == null || monsterPrefabs.Length == 0) { return; }

            _monsters = new MonsterState[monsterCount];
            for (var i = 0; i < monsterCount; i++) {
                var prefab = monsterPrefabs[Random.Range(0, monsterPrefabs.Length)];
                var instance = Instantiate(prefab, transform);
                instance.name = $"Monster_{i}";
                instance.transform.localScale =
                        new Vector3(monsterScale, monsterScale, monsterScale);

                var startPos = RandomWanderPoint();
                instance.transform.localPosition = startPos;

                foreach (var renderer in instance.GetComponentsInChildren<Renderer>()) {
                    renderer.sortingOrder = 103;
                }
                RendererViewportClipper.Attach(instance);

                var animator = instance.GetComponent<Animator>();
                if (animator != null) { animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; }

                _monsters[i] = new MonsterState {
                    instance = instance,
                    animator = animator,
                    state = MonsterStateType.Idle,
                    targetPosition = startPos,
                    timer = Random.Range(minIdleDuration, maxIdleDuration),
                    facingRight = true
                };
            }
        }

        private Vector3 RandomWanderPoint() {
            var angle = Random.Range(0f, Mathf.PI * 2f);
            var dist = Random.Range(0f, wanderRadius);
            return new Vector3(Mathf.Cos(angle) * dist, Mathf.Sin(angle) * dist, 0f);
        }

        void Update() {
            if (_monsters == null) { return; }
            foreach (var monster in _monsters) { UpdateMonster(monster); }
        }

        private void UpdateMonster(MonsterState monster) {
            if (monster.instance == null) { return; }

            switch (monster.state) {
                case MonsterStateType.Idle: UpdateIdle(monster); break;
                case MonsterStateType.Walking: UpdateWalking(monster); break;
                case MonsterStateType.Action: UpdateAction(monster); break;
            }
        }

        private void UpdateIdle(MonsterState monster) {
            monster.timer -= Time.deltaTime;
            if (monster.timer > 0f) { return; }

            // Transition to walking toward a new random point
            monster.targetPosition = RandomWanderPoint();
            monster.state = MonsterStateType.Walking;
            if (monster.animator != null) { monster.animator.Play(MoveStateHash); }

            // Flip sprite to face direction of travel
            var direction = monster.targetPosition - monster.instance.transform.localPosition;
            if (Mathf.Abs(direction.x) > 0.01f) {
                var movingRight = direction.x > 0f;
                if (movingRight != monster.facingRight) {
                    monster.facingRight = movingRight;
                    var scale = monster.instance.transform.localScale;
                    scale.x = monster.facingRight ? -monsterScale : monsterScale;
                    monster.instance.transform.localScale = scale;
                }
            }
        }

        private void UpdateWalking(MonsterState monster) {
            var pos = monster.instance.transform.localPosition;
            var step = moveSpeed * Time.deltaTime;
            monster.instance.transform.localPosition =
                    Vector3.MoveTowards(pos, monster.targetPosition, step);

            if (Vector3.Distance(monster.instance.transform.localPosition, monster.targetPosition) <
                0.5f) {
                // Arrived — either perform an action or idle
                if (Random.value < actionChance) {
                    monster.state = MonsterStateType.Action;
                    if (monster.animator != null) {
                        var trigger = Random.value < 0.5f ? AttackTrigger : SpecialATrigger;
                        monster.animator.SetTrigger(trigger);
                    }
                } else {
                    EnterIdle(monster);
                }
            }
        }

        private void UpdateAction(MonsterState monster) {
            if (monster.animator == null) {
                EnterIdle(monster);
                return;
            }

            // Wait for the action animation to finish (transitions back to Idle or Move)
            if (monster.animator.IsInTransition(0)) { return; }
            var stateInfo = monster.animator.GetCurrentAnimatorStateInfo(0);
            if (stateInfo.shortNameHash == IdleStateHash ||
                stateInfo.shortNameHash == MoveStateHash) {
                EnterIdle(monster);
            }
        }

        private void EnterIdle(MonsterState monster) {
            monster.state = MonsterStateType.Idle;
            monster.timer = Random.Range(minIdleDuration, maxIdleDuration);
            if (monster.animator != null) { monster.animator.Play(IdleStateHash); }
        }

        [ContextMenu("Test: All Idle")]
        public void TestAllIdle() { ForEachMonster(m => m.animator?.Play(IdleStateHash)); }

        [ContextMenu("Test: All Move")]
        public void TestAllMove() { ForEachMonster(m => m.animator?.Play(MoveStateHash)); }

        [ContextMenu("Test: All Attack")]
        public void TestAllAttack() { ForEachMonster(m => m.animator?.SetTrigger(AttackTrigger)); }

        [ContextMenu("Test: All SpecialAttack")]
        public void TestAllSpecialAttack() {
            ForEachMonster(m => m.animator?.SetTrigger(SpecialATrigger));
        }

        private void ForEachMonster(System.Action<MonsterState> action) {
            if (_monsters == null) { return; }
            foreach (var monster in _monsters) {
                if (monster.instance != null) {
                    monster.state = MonsterStateType.Idle;
                    monster.timer = 5f;
                    action(monster);
                }
            }
        }
    }
}
