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

namespace StandardScene.Signal.Logic
{
    /// <summary>
    /// 机构进出站握手。对齐反编译 <c>DefaultPlugin.JGControl</c> / <c>JGJudge</c> / <c>RequestIn</c> / <c>Arrived</c>。
    /// </summary>
    /// <remarks>
    /// <para>
    /// <c>SignalParams</c> 分号三段：<c>机构名;动作;限流</c>。
    /// 动作 <c>RequestIn</c>（请求进入，配在机构口外等待点）或 <c>Arrived</c>（到位，配在机构内地标）。
    /// 第三段可选，格式与独立限流不同：<c>区域-车组-限额-点1,点2</c>（短横分隔，见 <see cref="RateFlowHandler"/>）。
    /// </para>
    /// <para>
    /// RequestIn 放行条件（需同时满足）：PLC 读字节=允许进入、尚无请求进入车、写字节=无状态。
    /// 下线机构额外要求 <c>JgPointId</c> 上没有其它车。通过后写「进入中」、记下 RequestInAgvNo、停充并启动。
    /// </para>
    /// <para>
    /// 车已在跑但本车不是请求进入车、且 PLC 不是允许进入时，立即停车（停稳拍与行驶拍都会判）。
    /// Arrived：若 InAgvNo 还不是本车，写「到位」、登记 InAgvNo、清空 RequestInAgvNo。
    /// 之后的「离开中 / 已离开」由 PLC Worker 的 <see cref="PlcStationLogic.AutoLeave"/> 推进。
    /// </para>
    /// </remarks>
    public static class JgControlHandler
    {
        /// <summary>停稳：可选限流 → RequestIn 或 Arrived。</summary>
        public static void OnStopped(Car car, SignalStopSpec spec, Func<string, string, PlcStationRuntime> find, IDictionary<string, int> rateFlowLog)
        {
            var jgName = spec.JgName;
            var action = spec.Action;
            var dockId = spec.DockId;
            var rateFlow = spec.ExtraParams;
            if (string.IsNullOrEmpty(jgName))
            {
                Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)}，读取配置机构名称为空", "JGControl", true);
                return;
            }

            if (!string.IsNullOrEmpty(rateFlow) && !RateFlowHandler.AllowPass(car, rateFlow, rateFlowLog))
            {
                Diagnosis.Log($"AGV{car.id}停在地标{SignalCarAdapter.PositionId(car)}，限流禁止通行", "JGControl", true);
                return;
            }

            if (string.Equals(action, "RequestIn", StringComparison.OrdinalIgnoreCase))
                RequestIn(jgName, dockId, car, find);
            else if (string.Equals(action, "Arrived", StringComparison.OrdinalIgnoreCase))
                Arrived(jgName, dockId, car, find);
        }

        /// <summary>行驶中只做 RequestIn 安全闸：未允许进入且不是本车占用请求槽则停车。</summary>
        public static void OnMoving(Car car, SignalStopSpec spec, Func<string, string, PlcStationRuntime> find)
        {
            var jgName = spec.JgName;
            var action = spec.Action;
            if (string.IsNullOrEmpty(jgName))
                return;
            if (string.Equals(action, "RequestIn", StringComparison.OrdinalIgnoreCase))
                RequestInJudge(jgName, spec.DockId, car, find);
        }

        private static void RequestIn(string jgName, string dockId, Car car, Func<string, string, PlcStationRuntime> find)
        {
            var rt = find(jgName, dockId);
            if (rt == null)
            {
                Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
                return;
            }

            lock (rt.Sync)
            {
                if (rt.ReadSignal == SignalReadValue.允许进入 &&
                    rt.RequestInAgvNo == 0 &&
                    rt.ReadWriteSignal == SignalWriteValue.无状态)
                {
                    if (rt.Station.LineType is SignalLineType.单牵引下线机构 or SignalLineType.双牵引下线机构)
                    {
                        var inside = SignalCarAdapter.CarsAt(rt.Dock.JgPointId);
                        if (inside.Count > 0)
                        {
                            Diagnosis.Log(
                                $"{rt.DisplayName} 机构内有AGV【{string.Join(",", inside.Select(x => x.id))}】暂不放行AGV{car.id}",
                                "JGControl", true);
                            return;
                        }
                    }

                    Diagnosis.Log($"{rt.DisplayName} 机构允许进入，通知AGV{car.id}启动，通知机构AGV进入中", "JGControl", true);
                    rt.WriteSignal = SignalWriteValue.进入中;
                    rt.RequestInAgvNo = car.id;
                    SignalCarAdapter.StopCharge(car);
                    SignalCarAdapter.Start(car);
                    return;
                }

                if (rt.ReadSignal != SignalReadValue.允许进入 &&
                    rt.RequestInAgvNo != car.id &&
                    SignalCarAdapter.IsMoving(car))
                {
                    SignalCarAdapter.Stop(car);
                    Diagnosis.Log($"{rt.DisplayName} 机构不允许进入，监控到AGV启动，暂停AGV{car.id}", "JGControl", true);
                }
            }
        }

        private static void RequestInJudge(string jgName, string dockId, Car car, Func<string, string, PlcStationRuntime> find)
        {
            var rt = find(jgName, dockId);
            if (rt == null)
            {
                Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
                return;
            }

            lock (rt.Sync)
            {
                if (rt.ReadSignal != SignalReadValue.允许进入 &&
                    rt.RequestInAgvNo != car.id &&
                    SignalCarAdapter.IsMoving(car))
                {
                    SignalCarAdapter.Stop(car);
                    Diagnosis.Log($"{rt.DisplayName} 机构不允许进入，监控到AGV启动，暂停AGV{car.id}", "JGControl", true);
                }
            }
        }

        private static void Arrived(string jgName, string dockId, Car car, Func<string, string, PlcStationRuntime> find)
        {
            var rt = find(jgName, dockId);
            if (rt == null)
            {
                Diagnosis.Log($"{jgName} 未能找到机构", "JGControl", true);
                return;
            }

            lock (rt.Sync)
            {
                if (rt.InAgvNo == car.id)
                    return;
                Diagnosis.Log($"AGV{car.id}已到达机构{rt.DisplayName}", "JGControl", true);
                rt.WriteSignal = SignalWriteValue.到位;
                rt.InAgvNo = car.id;
                rt.RequestInAgvNo = 0;
            }
        }
    }
}
