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

namespace Gyvr.Mythril2D
{
    public enum WaypointLoopMode
    {
        Cycle,
        Mirrored
    }

    [Serializable]
    public class AIWaypointController : AIController
    {
        [Header("Waypoint Movement Settings")]
        [SerializeField] private bool enableWaypointMovement = false;
        [SerializeField] private List<Waypoint> waypoints = new();
        [SerializeField] private bool enableLoopMode = true;
        [SerializeField] private WaypointLoopMode loopMode = WaypointLoopMode.Cycle;

        [Header("Idle Movement Settings")]
        [SerializeField] private bool enableIdleMovement = true;
        [SerializeField, Min(0.1f)] private float idleRadius = 2.0f;
        [SerializeField, Min(0.1f)] private float idleMovementInterval = 3.0f;

        private Vector2 m_initialPositionLocal;
        private Vector2 idleTargetPosition;
        private float idleTimer;
        private int currentWaypointIndex = 0;
        private float waypointPauseTimer = 0.0f;
        private bool isReversing = false;
        private int lastVisitedWaypointIndex = 0;

        protected override void OnStart()
        {
            base.OnStart();
            if (m_subject != null)
            {
                m_initialPositionLocal = m_subject.transform.position;
            }
        }

        private void UpdateWaypointMovement()
        {
            if (HasTarget()) return;

            Waypoint lastVisitedWaypoint = waypoints[lastVisitedWaypointIndex];
            Waypoint targetWaypoint = waypoints[currentWaypointIndex];
            Vector2 directionToWaypoint = (Vector2)targetWaypoint.transform.position - (Vector2)m_subject.transform.position;

            if (waypointPauseTimer > 0.0f)
            {
                waypointPauseTimer -= Time.deltaTime;

                if (lastVisitedWaypoint.roamAtWaypoint)
                {
                    UpdateRandomIdleMovement();
                }
                else
                {
                    m_subject.SetMovementDirection(Vector2.zero);
                }

                return;
            }

            if (directionToWaypoint.magnitude > 0.1f)
            {
                m_subject.SetMovementDirection(directionToWaypoint.normalized);
            }
            else
            {
                m_subject.SetMovementDirection(Vector2.zero);
                waypointPauseTimer = targetWaypoint.pauseDuration;
                targetWaypoint.ExecuteWaypointCommand();
                lastVisitedWaypointIndex = currentWaypointIndex;

                if (enableLoopMode)
                {
                    if (loopMode == WaypointLoopMode.Cycle)
                    {
                        if (currentWaypointIndex + 1 < waypoints.Count)
                        {
                            currentWaypointIndex++;
                        }
                        else
                        {
                            currentWaypointIndex = 0;
                        }
                    }
                    else if (loopMode == WaypointLoopMode.Mirrored)
                    {
                        if (!isReversing)
                        {
                            if (currentWaypointIndex + 1 < waypoints.Count)
                            {
                                currentWaypointIndex++;
                            }
                            else
                            {
                                isReversing = true;
                                currentWaypointIndex--;
                            }
                        }
                        else
                        {
                            if (currentWaypointIndex > 0)
                            {
                                currentWaypointIndex--;
                            }
                            else
                            {
                                isReversing = false;
                                currentWaypointIndex++;
                            }
                        }
                    }
                }
                else
                {
                    if (currentWaypointIndex + 1 < waypoints.Count)
                    {
                        currentWaypointIndex++;
                    }
                }
            }
        }

        private void UpdateIdleMovement()
        {
            if (HasTarget()) return;

            if (enableWaypointMovement && waypoints.Count > 0)
            {
                UpdateWaypointMovement();
            }
            else if (enableIdleMovement)
            {
                UpdateRandomIdleMovement();
            }
        }

        private void UpdateRandomIdleMovement()
        {
            if (HasTarget()) return;

            idleTimer -= Time.deltaTime;

            if (idleTimer <= 0.0f)
            {
                idleTimer = UnityEngine.Random.Range(idleMovementInterval * 0.5f, idleMovementInterval * 1.5f);
                if (enableWaypointMovement && waypoints.Count > 0)
                {
                    Waypoint currentWaypoint = waypoints[lastVisitedWaypointIndex];
                    idleTargetPosition = (Vector2)currentWaypoint.transform.position + UnityEngine.Random.insideUnitCircle * idleRadius;
                }
                else
                {
                    idleTargetPosition = m_initialPositionLocal + UnityEngine.Random.insideUnitCircle * idleRadius;
                }
            }

            Vector2 directionToIdleTarget = idleTargetPosition - (Vector2)m_subject.transform.position;
            if (directionToIdleTarget.magnitude > 0.1f)
            {
                m_subject.SetMovementDirection(directionToIdleTarget.normalized);
            }
            else
            {
                m_subject.SetMovementDirection(Vector2.zero);
            }
        }

        protected override void OnFixedUpdate()
        {
            base.OnFixedUpdate();
            UpdateIdleMovement();
        }
    }
}