using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using SimpleCore;
using SimpleCore.Library;
using SimpleLite;
using SimpleLite.Props;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using StandardScene.CarTypes;
using StandardScene.Chained;
using StandardScene.Magnetic.Tasking;
using StandardScene.Model;

namespace StandardScene
{
    /// <summary>
    /// 磁导航 FASS 2.0 环线任务进程。
    /// <para>任务分配/触发/流量逻辑继承 Core <see cref="LoopMission"/>。</para>
    /// <para>导航执行由 <see cref="Mag2Car"/> 拦截 Loop 编译脚本（含 <c>Mag2Go</c> + <c>goalSite</c>），
    /// 改为单次全程 <c>0xB1</c> 状态机任务。</para>
    /// </summary>
    [MissionType(Name = "磁导航FASS2环线", editor = typeof(Mag2LoopMission))]
    public class Mag2LoopMission : LoopMission
    {
        [JsonIgnore] public override MissionStatus status { get; set; } = new LoopMissionStatus();

        /// <summary>
        /// Mag2 空闲时可能尚未 TrafficReset（holdingLocks 为空），仍按上报站点/siteID 匹配在站车辆，
        /// 否则 AutoLoop 永远找不到车、加不上 goalSite。
        /// </summary>
        protected override Car FindCarArrivedAtSite(int siteId)
        {
            var byLock = base.FindCarArrivedAtSite(siteId);
            if (byLock != null)
                return byLock;

            try
            {
                return SimpleLib.GetAllCars()
                    .OfType<Mag2Car>()
                    .FirstOrDefault(car =>
                    {
                        if (car?.tags == null || car.tags.Contains("occupied") || !car.tags.Contains("Online"))
                            return false;
                        if (car.status?.pendingLocks != null && car.status.pendingLocks.Length > 0)
                            return false;
                        if (car.status?.holdingLocks != null && car.status.holdingLocks.Length > 1)
                            return false;

                        var physical = car.siteID > 0 ? car.siteID : car.GetLastSite();
                        return physical == siteId;
                    });
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 分配前尽量补上本站交管锁，保证 SelectCar/GoSite 的 GetLastSite 可用。
        /// </summary>
        protected override void AssignCarToTarget(Car car, int targetSiteId)
        {
            if (car is Mag2Car mag2)
            {
                EnsureMag2HoldingCurrentSite(mag2);
            }

            base.AssignCarToTarget(car, targetSiteId);
        }

        /// <summary>
        /// 用当前占点匹配全部 LoopTask 展开路径（不过滤 IsViaPoint）。
        /// 路径用 BFS，避免 FindRoute 污染交管锁。
        /// </summary>
        public static List<Fass2ChainMatch> FindChainsContaining(int siteId)
        {
            var matches = new List<Fass2ChainMatch>();
            if (siteId <= 0)
            {
                return matches;
            }

            IEnumerable<AbstractLoopMission> missions = null;
            try
            {
                missions = SimpleProject.proj?.Missions?.OfType<AbstractLoopMission>();
            }
            catch
            {
                missions = null;
            }

            if (missions == null)
            {
                return matches;
            }

            foreach (var mission in missions)
            {
                IReadOnlyList<LoopTask> tasks;
                try
                {
                    tasks = mission.GetTasks();
                }
                catch
                {
                    continue;
                }

                if (tasks == null)
                {
                    continue;
                }

                foreach (var task in tasks)
                {
                    var match = TryMatchTask(task, siteId);
                    if (match != null)
                    {
                        matches.Add(match);
                    }
                }
            }

            return matches;
        }

        public static bool TryResolveBelongingChain(
            int siteId,
            int? preferGoalSiteId,
            out Fass2ChainMatch selected,
            out string reason)
        {
            var matches = FindChainsContaining(siteId);
            return Fass2ReconnectChainSelector.TrySelect(matches, preferGoalSiteId, out selected, out reason);
        }

        private static Fass2ChainMatch TryMatchTask(LoopTask task, int siteId)
        {
            if (task == null || task.CurrentStationId <= 0 || task.TargetStationId <= 0)
            {
                return null;
            }

            List<int> fullPath;
            try
            {
                fullPath = Fass2RouteHelper.GetSitesBetween(task.CurrentStationId, task.TargetStationId, null);
            }
            catch
            {
                return null;
            }

            if (fullPath == null || fullPath.Count == 0)
            {
                return null;
            }

            var index = fullPath.IndexOf(siteId);
            if (index < 0)
            {
                return null;
            }

            var remaining = fullPath.Skip(index).ToList();
            return new Fass2ChainMatch
            {
                TaskId = task.Id,
                TaskPriority = task.Priority,
                CurrentSiteId = siteId,
                TargetSiteId = task.TargetStationId,
                IndexInPath = index,
                DistanceToTarget = Math.Max(0, fullPath.Count - index - 1),
                IsAtStartPoint = index == 0,
                IsAtEndPoint = index == fullPath.Count - 1,
                FullPath = fullPath,
                RemainingPath = remaining
            };
        }

        private static void EnsureMag2HoldingCurrentSite(Mag2Car car)
        {
            try
            {
                if (car.status?.holdingLocks != null && car.status.holdingLocks.Length == 1)
                    return;

                var siteId = car.siteID > 0 ? car.siteID : car.GetLastSite();
                if (siteId <= 0)
                    return;

                var site = SimpleLib.GetSite(siteId);
                if (site == null)
                    return;

                car.TrafficReset(site, true, strict: false);
            }
            catch (Exception)
            {
                // 交管失败时仍允许打上 goalSite，后续 GoSite/状态机会再处理
            }
        }
    }
}
