using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using SimpleCore.Library;
using SimpleLite.RCS.CarTypes;
using StandardScene.Signal.Model;
using StandardScene.Signal.Plc;

namespace StandardScene.Signal.Logic
{
    /// <summary>
    /// 1s 扫全场车，对齐反编译 <c>DefaultPlugin.ExcuteThreadMethod</c> + <c>StarSignManage</c>。
    /// </summary>
    /// <remarks>
    /// 每辆车每拍只看当前站点：
    /// <list type="number">
    /// <item>停稳：先按握手点类型分发 Handler，再执行放行点（放行点不读 PLC，可能把还在等允许进入的车开走，站点不要两边都配）。</item>
    /// <item>行驶中：仅 JGControl + RequestIn 调用 <c>RequestInJudge</c>，PLC 未允许进入则停车。</item>
    /// </list>
    /// 握手点解析优先站点 fields（<see cref="SignalCarAdapter.TryReadSignalStop"/>），没有再查 JSON。
    /// </remarks>
    public sealed class CarScanWorker : IDisposable
    {
        /// <summary>取当前全部机构运行态；由 Mission 提供，内部会拷贝列表。</summary>
        private readonly Func<IReadOnlyList<PlcStationRuntime>> _runtimes;

        /// <summary>扫车间隔，下限 100ms，默认跟进程 TickMs=1000。</summary>
        private readonly int _tickMs;

        /// <summary>保护握手点 / 放行点字典，热替换配置时与扫车拍互斥。</summary>
        private readonly object _configLock = new object();

        /// <summary>站点 → 握手点。同一站点多条配置只留第一条。</summary>
        private Dictionary<int, HandshakePointModel> _handshake = new Dictionary<int, HandshakePointModel>();

        /// <summary>站点 → 放行点。同一站点多条配置只留第一条。</summary>
        private Dictionary<int, ReleasePointModel> _release = new Dictionary<int, ReleasePointModel>();

        /// <summary>限流区域上次记日志的车号，避免同一区域每秒刷屏。</summary>
        private readonly Dictionary<string, int> _rateFlowLog = new Dictionary<string, int>();

        /// <summary>车辆没有 GetChargeTime 时，用首次看到「充电中」的时刻估算秒数。</summary>
        private readonly Dictionary<int, DateTime> _chargeStarted = new Dictionary<int, DateTime>();

        /// <summary>未知 SignalType 的日志节流（同站点 10s 一次）。</summary>
        private readonly Dictionary<int, DateTime> _unknownTypeLog = new Dictionary<int, DateTime>();

        private CancellationTokenSource _cts;
        private Thread _thread;
        private int _tickCount;

        public CarScanWorker(Func<IReadOnlyList<PlcStationRuntime>> runtimes, int tickMs)
        {
            _runtimes = runtimes ?? throw new ArgumentNullException(nameof(runtimes));
            _tickMs = Math.Max(100, tickMs);
        }

        /// <summary>已完成的扫车拍数，写入进程 status 供监视。</summary>
        public int TickCount => _tickCount;

        /// <summary>
        /// 热替换握手点 / 放行点。过滤掉站点号无效或信号类型为空的握手点。
        /// 不中断线程，下一拍生效。
        /// </summary>
        public void ReplaceConfig(IEnumerable<HandshakePointModel> handshake, IEnumerable<ReleasePointModel> release)
        {
            lock (_configLock)
            {
                _handshake = (handshake ?? Array.Empty<HandshakePointModel>())
                    .Where(x => x != null && x.Sit > 0 && !string.IsNullOrWhiteSpace(x.SignalType))
                    .GroupBy(x => x.Sit)
                    .ToDictionary(g => g.Key, g => g.First());
                _release = (release ?? Array.Empty<ReleasePointModel>())
                    .Where(x => x != null && x.Sit > 0)
                    .GroupBy(x => x.Sit)
                    .ToDictionary(g => g.Key, g => g.First());
            }
        }

        /// <summary>启动后台扫车线程。重复 Start 若线程仍活则忽略。</summary>
        public void Start()
        {
            if (_thread != null && _thread.IsAlive) return;
            _cts = new CancellationTokenSource();
            _thread = new Thread(Loop)
            {
                IsBackground = true,
                Name = "SignalScan"
            };
            _thread.Start();
            Diagnosis.Log("扫车握手线程已启动", "Signal", true);
        }

        /// <summary>取消令牌并最多等 2s 退出。不抛异常，供进程停止时调用。</summary>
        public void Stop()
        {
            try { _cts?.Cancel(); }
            catch { }
            try { _thread?.Join(2000); }
            catch { }
            _thread = null;
            Diagnosis.Log("扫车握手线程已停止", "Signal", true);
        }

        public void Dispose() => Stop();

        private void Loop()
        {
            var token = _cts.Token;
            while (!token.IsCancellationRequested)
            {
                try
                {
                    ScanOnce();
                    Interlocked.Increment(ref _tickCount);
                }
                catch (Exception ex)
                {
                    Diagnosis.Log($"检测信号停止的AGV是否可以放行异常：{ex.Message}", "Signal", true);
                }

                try { Thread.Sleep(_tickMs); }
                catch (ThreadInterruptedException) { break; }
            }
        }

        /// <summary>
        /// 一拍：拷贝配置字典 → 按机构名查找闭包 → 遍历全部车。
        /// 查找机构时忽略大小写，与 JSON 里 JgName 对齐。
        /// </summary>
        internal void ScanOnce()
        {
            Dictionary<int, HandshakePointModel> handshake;
            Dictionary<int, ReleasePointModel> release;
            lock (_configLock)
            {
                handshake = _handshake;
                release = _release;
            }

            PlcStationRuntime Find(string name, string dockId)
            {
                if (string.IsNullOrWhiteSpace(name))
                    return null;
                var list = _runtimes() ?? Array.Empty<PlcStationRuntime>();
                var ofStation = list.Where(x =>
                    string.Equals(x.JgName, name, StringComparison.OrdinalIgnoreCase)).ToList();
                if (ofStation.Count == 0)
                    return null;
                if (!string.IsNullOrWhiteSpace(dockId))
                {
                    var hit = ofStation.FirstOrDefault(x =>
                        string.Equals(x.DockId, dockId.Trim(), StringComparison.OrdinalIgnoreCase));
                    if (hit != null)
                        return hit;
                }

                return ofStation.FirstOrDefault(x =>
                           string.Equals(x.DockId, PlcConfigLoader.DefaultDockId, StringComparison.OrdinalIgnoreCase))
                       ?? ofStation[0];
            }

            foreach (var car in SignalCarAdapter.All())
            {
                if (car == null) continue;
                var sit = SignalCarAdapter.PositionId(car);
                var spec = ResolveSpec(sit, handshake);

                if (SignalCarAdapter.IsStopped(car))
                {
                    if (spec != null)
                        DispatchStopped(car, spec, Find);
                    ReleasePointHandler.OnStopped(car, sit, release);
                }
                else if (spec != null && spec.Is("JGControl"))
                {
                    JgControlHandler.OnMoving(car, spec, Find);
                }
            }
        }

        /// <summary>
        /// 站点 fields 有 SignalType 则用地图点配置（老 SignalStop）；
        /// 否则用 handshake-points.json。fields 存在但类型为空视为本站不握手。
        /// </summary>
        private SignalStopSpec ResolveSpec(int sit, IReadOnlyDictionary<int, HandshakePointModel> handshake)
        {
            if (sit <= 0) return null;

            if (SignalCarAdapter.TryReadSignalStop(sit, out var type, out var parms))
            {
                if (string.IsNullOrWhiteSpace(type))
                    return null;
                return SignalStopSpec.Parse(type, parms);
            }

            if (handshake != null && handshake.TryGetValue(sit, out var model))
                return SignalStopSpec.From(model);

            return null;
        }

        /// <summary>
        /// 停稳分发。TimedCharging 优先：充电点不应再走机构逻辑。
        /// 未识别的 SignalType 按站点节流打日志，避免刷屏。
        /// </summary>
        private void DispatchStopped(Car car, SignalStopSpec spec, Func<string, string, PlcStationRuntime> find)
        {
            if (spec.Is("TimedCharging"))
            {
                TimedChargeHandler.OnStopped(car, spec, _chargeStarted);
                return;
            }

            if (spec.Is("JGControl"))
            {
                JgControlHandler.OnStopped(car, spec, find, _rateFlowLog);
                return;
            }

            if (spec.Is("PointControl"))
            {
                PointControlHandler.OnStopped(car, spec, find);
                return;
            }

            if (spec.Is("RateFlowControl"))
            {
                RateFlowHandler.OnStopped(car, spec, _rateFlowLog);
                return;
            }

            var sit = SignalCarAdapter.PositionId(car);
            if (_unknownTypeLog.TryGetValue(sit, out var last) && (DateTime.Now - last).TotalSeconds < 10)
                return;
            _unknownTypeLog[sit] = DateTime.Now;
            Diagnosis.Log($"信号类型【{spec.SignalType}】未找到匹配的业务处理模块", "Signal", true);
        }
    }
}
