using System;
using System.Collections.Generic;
using System.Globalization;
using SimpleLite.RCS.CarTypes;

namespace StandardScene.Signal.Logic
{
    /// <summary>
    /// 磁条管控区占用判定：他车占用「当前策略」管控站点列表的数量 ≥ 容量则不放行；本车不计入。
    /// 磁条交管进程只对停在触发点的 MagCar 调用，满足后发启动。
    /// </summary>
    public static class MagControlAreaGate
    {
        public const byte StartStopPass = 1;
        public const byte StartStopControlStart = 11;

        private static readonly char[] SiteIdSeparators = { ',', ';', '|', ' ', '\t', '[', ']', '(', ')', '{', '}' };

        public static byte NormalizeReleaseStartStop(byte value)
        {
            if (value == StartStopPass || value == StartStopControlStart)
                return value;
            return StartStopControlStart;
        }

        public static int NormalizeCapacity(int capacity)
        {
            return capacity < 1 ? 1 : capacity;
        }

        public static int[] ParseSiteIds(string text, int fallbackSiteId)
        {
            var ids = new List<int>();
            if (!string.IsNullOrWhiteSpace(text))
            {
                var parts = text.Split(SiteIdSeparators, StringSplitOptions.RemoveEmptyEntries);
                foreach (var part in parts)
                {
                    if (int.TryParse(part.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var id) &&
                        id > 0 && !ids.Contains(id))
                    {
                        ids.Add(id);
                    }
                }
            }

            if (ids.Count == 0 && fallbackSiteId > 0)
                ids.Add(fallbackSiteId);

            return ids.ToArray();
        }

        public static string NormalizeCompatGroup(string value)
        {
            return (value ?? string.Empty).Trim();
        }

        public static bool SitesIntersect(IReadOnlyList<int> a, IReadOnlyList<int> b)
        {
            if (a == null || b == null || a.Count == 0 || b.Count == 0)
                return false;
            for (var i = 0; i < a.Count; i++)
            {
                var left = a[i];
                if (left <= 0)
                    continue;
                for (var j = 0; j < b.Count; j++)
                {
                    if (b[j] == left)
                        return true;
                }
            }

            return false;
        }

        public static MagControlReleaseDecision Evaluate(
            int selfCarId,
            int triggerSit,
            IReadOnlyList<int> areaSiteIds,
            int capacity,
            byte releaseStartStop,
            IReadOnlyList<(int CarId, IReadOnlyList<int> OccupiedSiteIds)> occupancies)
        {
            var sites = areaSiteIds == null || areaSiteIds.Count == 0
                ? (triggerSit > 0 ? new[] { triggerSit } : Array.Empty<int>())
                : areaSiteIds;
            capacity = NormalizeCapacity(capacity);
            releaseStartStop = NormalizeReleaseStartStop(releaseStartStop);

            var others = 0;
            if (occupancies != null)
            {
                foreach (var occupancy in occupancies)
                {
                    if (occupancy.CarId == selfCarId)
                        continue;
                    if (OccupiesListedSites(occupancy.OccupiedSiteIds, sites))
                        others++;
                }
            }

            var canRelease = others < capacity;
            var areaId = string.Join(",", sites);
            return new MagControlReleaseDecision
            {
                RuleFound = true,
                CanRelease = canRelease,
                AreaId = areaId,
                Capacity = capacity,
                OthersInArea = others,
                ReleaseStartStop = releaseStartStop,
                Reason = canRelease
                    ? "area clear"
                    : $"area occupied cars={others}, capacity={capacity}"
            };
        }

        /// <summary>统计占用管控区内部站点的车辆数，可排除排队车和在途车。</summary>
        public static int CountOccupyingCars(
            IReadOnlyList<(int CarId, IReadOnlyList<int> OccupiedSiteIds)> occupancies,
            IReadOnlyList<int> areaSiteIds,
            HashSet<int> excludeCarIds)
        {
            if (occupancies == null || occupancies.Count == 0 ||
                areaSiteIds == null || areaSiteIds.Count == 0)
                return 0;

            var others = 0;
            foreach (var occupancy in occupancies)
            {
                if (excludeCarIds != null && excludeCarIds.Contains(occupancy.CarId))
                    continue;
                if (OccupiesListedSites(occupancy.OccupiedSiteIds, areaSiteIds))
                    others++;
            }

            return others;
        }

        public static bool OccupiesListedSites(IReadOnlyList<int> occupiedSiteIds, IReadOnlyList<int> areaSiteIds)
        {
            if (occupiedSiteIds == null || occupiedSiteIds.Count == 0 ||
                areaSiteIds == null || areaSiteIds.Count == 0)
                return false;

            for (var i = 0; i < occupiedSiteIds.Count; i++)
            {
                var occupied = occupiedSiteIds[i];
                if (occupied <= 0)
                    continue;
                for (var j = 0; j < areaSiteIds.Count; j++)
                {
                    if (areaSiteIds[j] == occupied)
                        return true;
                }
            }

            return false;
        }

        /// <summary>统计一辆车占用的站点：物理 siteID + holdingLocks。</summary>
        public static IReadOnlyList<int> CollectOccupiedSiteIds(Car car)
        {
            var ids = new List<int>();
            if (car == null)
                return ids;
            try
            {
                if (car.siteID > 0)
                    ids.Add(car.siteID);
            }
            catch
            {
            }

            var holding = car.status?.holdingLocks;
            if (holding == null)
                return ids;
            foreach (var lockId in holding)
            {
                if (lockId > 0 && !ids.Contains(lockId))
                    ids.Add(lockId);
            }

            return ids;
        }
    }
}
