using System;
using System.Collections.Generic;
using System.Linq;
using Schema;
using UnityEngine;
using UnityEngine.AI;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Util;
using Action = Schema.Action;

namespace VOID.Generic.AI.Schema.Actions
{
    [Description("Gets point where ThisUnit can go with current MovementPoints towards given destination point")]
    [Category(SchemaCategory.CombatThisUnit)]
    public class GetReachablePosition : Action
    {
        private enum DestinationType
        {
            Position,
            Unit
        }
        
         [SerializeField] private DestinationType _destinationType;
         [SerializeField] private BlackboardEntrySelector<UnitObject> _toUnit;
         [SerializeField] private BlackboardEntrySelector<Vector3> _toPosition;
         [SerializeField, WriteOnly, Space(15)] private BlackboardEntrySelector<Vector3> _saveTo;

        public override NodeStatus Tick(object nodeMemory, SchemaAgent agent)
        {
            var thisUnit = ((UnitObjectSchemaAgent)agent).unit;
            if (!thisUnit.basicState.turnManager) return NodeStatus.Failure;

            // Whole path to destination
            var path = _destinationType switch
            {
                DestinationType.Position => GetPathToPosition(thisUnit),
                DestinationType.Unit => GetPathToUnit(thisUnit),
                _ => throw new ArgumentOutOfRangeException()
            };
            var movePoints = thisUnit.unitData.currentResources.movePoints;

            // Path can't be calculated
            if (thisUnit.unitNavAgent.GetPath().status is NavMeshPathStatus.PathInvalid) return NodeStatus.Failure;
            
            // Reachable path (within move points range) and its last possible point
            NavMeshPathUtil.SplitPath(path.ToArray(), movePoints, out var reachablePath, out _);
            _saveTo.value = reachablePath.Last();
            
            return NodeStatus.Success;
        }

        private List<Vector3> GetPathToPosition(UnitObject thisUnit)
        {
            thisUnit.unitNavAgent.CalculatePathTo(_toPosition.value);
            return thisUnit.unitNavAgent.GetCorrectedPath();
        }

        private List<Vector3> GetPathToUnit(UnitObject thisUnit)
        {
            thisUnit.unitNavAgent.CalculatePathTo(_toUnit.value);
            return thisUnit.unitNavAgent.GetCorrectedPath();
        }
    }
}