using SimpleLite.RCS;
using SimpleCore;
using SimpleCore.PropType;
using System;
using System.Linq;
using SimpleLite.RCS.CarTypes;

namespace StandardScene.Scheduler.FassEvent
{
    /// <summary>
    /// 节点（地标）交管判断辅助类，替代 FASS <c>AlgorithmService</c> 中与 EventCar 相关的方法。
    /// <para>
    /// “锁定”判定依据 StandardScene 交通锁：holdingLocks、pendingLocks、aquiringLock，
    /// 以及站点 tags 中的 unavailable。
    /// </para>
    /// </summary>
    internal static class FassEventNodeHelper
    {
        /// <summary>指定节点列表是否全部未被任何车辆占用。</summary>
        public static bool NodeAllUnlocked(string[] nodeCodes)
        {
            return nodeCodes == null || nodeCodes.All(node => !IsNodeLocked(node, -1));
        }

        /// <summary>指定节点列表是否全部未被占用（排除当前车辆自身锁）。</summary>
        public static bool NodeAllUnlockedNotCar(string carCode, string[] nodeCodes)
        {
            var excludeCarId = ResolveCarId(carCode);
            return nodeCodes == null || nodeCodes.All(node => !IsNodeLocked(node, excludeCarId));
        }

        /// <summary>指定节点列表中是否存在任意一个被占用的节点。</summary>
        public static bool NodeAnyLocked(string[] nodeCodes)
        {
            return nodeCodes != null && nodeCodes.Any(node => IsNodeLocked(node, -1));
        }

        /// <summary>指定节点列表中是否存在被其他车辆占用的节点（排除自身）。</summary>
        public static bool NodeAnyLockedNotCar(string carCode, string[] nodeCodes)
        {
            var excludeCarId = ResolveCarId(carCode);
            return nodeCodes != null && nodeCodes.Any(node => IsNodeLocked(node, excludeCarId));
        }

        /// <summary>
        /// 节点全部解锁（排除自身）且指定节点范围内不存在处于运行态的其他车辆。
        /// 对应 FASS <c>NodeAllUnlockedNotCarNotEndCarState</c>。
        /// </summary>
        public static bool NodeAllUnlockedNotCarNotEndCarState(string carCode, string runningState, string[] nodeCodes)
        {
            if (!NodeAllUnlockedNotCar(carCode, nodeCodes))
            {
                return false;
            }

            return !ExistsRunningCarOnNodes(carCode, runningState, nodeCodes);
        }

        /// <summary>
        /// 判断除指定车辆外，是否有车辆在给定节点列表上处于“运行中”状态。
        /// 逻辑对齐 FASS <c>IsExistRunningStateCar</c>：支持首参 Contains 匹配及 Skip(1) 尾节点匹配。
        /// </summary>
        public static bool ExistsRunningCarOnNodes(string excludeCarCode, string runningState, string[] nodeCodes)
        {
            if (nodeCodes == null || nodeCodes.Length == 0)
            {
                return false;
            }

            var excludeCarId = ResolveCarId(excludeCarCode);
            foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
            {
                if (car.id == excludeCarId)
                {
                    continue;
                }

                var currentNode = FassEventCarSnapshotFactory.GetCurrentNodeCode(car);
                if (string.IsNullOrWhiteSpace(currentNode))
                {
                    continue;
                }

                var state = FassEventCarSnapshotFactory.GetFassState(car);
                if (!IsRunningState(state, runningState))
                {
                    continue;
                }

                // 与 FASS 一致：当前地标包含参数首项，或等于后续任一项。
                if (nodeCodes.Any(node => string.Equals(node, currentNode, StringComparison.OrdinalIgnoreCase)
                    || currentNode.Contains(node)))
                {
                    return true;
                }

                if (nodeCodes.Length > 1)
                {
                    var tailNodes = nodeCodes.Skip(1).ToArray();
                    if (tailNodes.Any(node => string.Equals(node, currentNode, StringComparison.OrdinalIgnoreCase)))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 判断单个地标是否被锁定。
        /// 节点号可解析为站点 ID，或通过 fields["TagValue"] 匹配地标标签。
        /// </summary>
        private static bool IsNodeLocked(string nodeCode, int excludeCarId)
        {
            if (!TryResolveSiteId(nodeCode, out var siteId))
            {
                return false;
            }

            var site = SimpleLib.GetSite(siteId);
            if (site?.tags?.Contains("unavailable") == true)
            {
                return true;
            }

            return SimpleLib.GetAllCars().Any(car =>
                car.id != excludeCarId &&
                (car.status.holdingLocks?.Contains(siteId) == true ||
                 car.status.pendingLocks?.Contains(siteId) == true ||
                 car.status.aquiringLock == siteId));
        }

        /// <summary>根据 FASS 车辆编号解析场景内 car.id。</summary>
        private static int ResolveCarId(string carCode)
        {
            if (string.IsNullOrWhiteSpace(carCode))
            {
                return -1;
            }

            var car = SimpleLib.GetAllCars()
                .OfType<Car>()
                .FirstOrDefault(item => string.Equals(FassEventCarSnapshotFactory.GetCarCode(item), carCode, StringComparison.OrdinalIgnoreCase));
            return car?.id ?? -1;
        }

        /// <summary>
        /// 将地标编码解析为站点 ID：纯数字直接查站；否则按 TagValue 字段匹配。
        /// </summary>
        private static bool TryResolveSiteId(string nodeCode, out int siteId)
        {
            siteId = 0;
            if (string.IsNullOrWhiteSpace(nodeCode))
            {
                return false;
            }

            if (int.TryParse(nodeCode, out siteId))
            {
                return SimpleLib.GetSite(siteId) != null;
            }

            var site = SimpleLib.GetAllSites().FirstOrDefault(item =>
                item.fields.TryGetValue("TagValue", out var tag) &&
                string.Equals(tag, nodeCode, StringComparison.OrdinalIgnoreCase));
            if (site == null)
            {
                return false;
            }

            siteId = site.id;
            return true;
        }

        /// <summary>
        /// 判断状态是否视为“运行中”。兼容 FASS 历史拼写 Runing 与 Running。
        /// </summary>
        private static bool IsRunningState(string state, string runningState)
        {
            if (string.IsNullOrWhiteSpace(state))
            {
                return false;
            }

            if (string.Equals(state, runningState, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            return string.Equals(state, "Running", StringComparison.OrdinalIgnoreCase) &&
                (string.Equals(runningState, "Runing", StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(runningState, "Running", StringComparison.OrdinalIgnoreCase));
        }
    }
}
