using IoTClient.Clients.PLC;
using IoTClient.Common.Enums;
using LessokajiWeaverUtilities.Utilities;
using Simple3.RCS;
using SimpleCore.Library;
using SimpleCore.PropType;
using StandardScene;
using StandardScene.CarTypes;
using StandardScene.Scheduler;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Simple3.RCS.CarTypes;

namespace StandardScene.Scheduler.FassEvent
{
    /// <summary>
    /// FASS 车辆事件核心处理器，逻辑对齐 <c>EventCarService</c>。
    /// <para>处理流程：TriggerHandler（触发匹配）→ ConditionHandler（条件 AND）→ ExecuteTask（Start/Stop）。</para>
    /// </summary>
    internal sealed class FassEventCarHandler
    {
        /// <summary>
        /// 防重复执行任务的车辆标签名。同一地标周期内只执行一次，换地标后由 EventCarMission 清除。
        /// 标签值为 <see cref="BuildTaskKey"/> 生成的任务指纹。
        /// </summary>
        internal const string ActiveTaskTag = "FassEvent:Active";

        private readonly EventCarMission _mission;

        /// <summary>PLC 读写串行锁，避免多车并发条件中同时 Open/Close 同一连接。</summary>
        private readonly object _plcLock = new object();

        /// <summary>JSON ConditionMethodName → 内置条件方法 映射表。</summary>
        private readonly Dictionary<string, Func<FassEventCarSnapshot, FassConditionEventConfig, bool>> _eventMethods;

        public FassEventCarHandler(EventCarMission mission)
        {
            _mission = mission;
            _eventMethods = BuildEventMethods();
        }

        /// <summary>
        /// 单次 TimerTick 对一辆车的处理入口（由 EventCarMission 按车 Task.Run，同车同时只跑一拍）。
        /// 仅处理 TriggerEvent=TimerTick 的配置项。
        /// </summary>
        public void HandleCarTimerTick(Car car, FassEventCarSnapshot snapshot, IReadOnlyList<FassEventCarConfig> eventCars)
        {
            foreach (var eventConfig in eventCars.Where(item => string.Equals(item.TriggerEvent, "TimerTick", StringComparison.OrdinalIgnoreCase)))
            {
                if (!TriggerHandler(snapshot, eventConfig))
                {
                    continue;
                }

                if (!ConditionHandler(car, snapshot, eventConfig))
                {
                    continue;
                }

                if (!eventConfig.TaskEnable)
                {
                    continue;
                }

                ExecuteTask(car, snapshot, eventConfig);
            }
        }

        /// <summary>注册与 FASS EventCarService.InitEventMethod 一致的条件方法名（保留历史拼写）。</summary>
        private Dictionary<string, Func<FassEventCarSnapshot, FassConditionEventConfig, bool>> BuildEventMethods()
        {
            return new Dictionary<string, Func<FassEventCarSnapshot, FassConditionEventConfig, bool>>(StringComparer.OrdinalIgnoreCase)
            {
                ["NodeAllUnlockedNotCar"] = NodeAllUnlockedNotCar,
                ["NodeAllUnlocked"] = NodeAllUnlocked,
                ["NodeAnyLockedNotCar"] = NodeAnyLockedNotCar,
                ["NodeAnyLocked"] = NodeAnyLocked,
                ["NodeAllUnlockedNotCarNotEndCarState"] = NodeAllUnlockedNotCarNotEndCarState,
                ["requestStaion"] = RequestStation,
                ["clearStaion"] = ClearStation,
                ["EmegerStop"] = EmergencyStop,
                ["EmegerStart"] = EmergencyStart,
                ["IsExistRunningStateCar"] = IsExistRunningStateCar,
                ["ChargeStart"] = ChargeStart
            };
        }

        /// <summary>
        /// 触发器匹配：车辆编号、前后地标、状态、角度等 CSV 过滤。
        /// 配置项为空表示“不限制”；车辆对应字段为空则无法匹配非空配置。
        /// </summary>
        private bool TriggerHandler(FassEventCarSnapshot snapshot, FassEventCarConfig config)
        {
            if (!MatchesCsvFilter(config.TriggerCarCode, snapshot.Code))
            {
                return false;
            }

            if (!MatchesCsvFilter(config.TriggerCarPrevNodeCode, snapshot.PrevNodeCode))
            {
                return false;
            }

            if (!MatchesCsvFilter(config.TriggerCarCurrentNodeCode, snapshot.CurrentNodeCode))
            {
                return false;
            }

            if (!MatchesCsvFilter(config.TriggerCarNextNodeCode, snapshot.NextNodeCode))
            {
                return false;
            }

            if (!MatchesCsvFilter(config.TriggerCarState, snapshot.State))
            {
                return false;
            }

            if (!MatchesCsvFilter(config.TriggerCarAngle, snapshot.Angle.ToString(CultureInfo.InvariantCulture)))
            {
                return false;
            }

            return true;
        }

        /// <summary>所有 ConditionEvents 必须全部通过（逻辑与）。</summary>
        private bool ConditionHandler(Car car, FassEventCarSnapshot snapshot, FassEventCarConfig config)
        {
            if (config.ConditionEvents == null || config.ConditionEvents.Count == 0)
            {
                return true;
            }

            foreach (var condition in config.ConditionEvents)
            {
                if (!SingleConditionHandler(car, snapshot, condition))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>单条条件分发：Method / Assembly / Plugin。</summary>
        private bool SingleConditionHandler(Car car, FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            if (!condition.ConditionEnable)
            {
                return true;
            }

            var conditionType = condition.ConditionType ?? "Method";
            if (string.Equals(conditionType, "Method", StringComparison.OrdinalIgnoreCase))
            {
                return MethodInvoke(snapshot, condition);
            }

            if (string.Equals(conditionType, "Assembly", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(conditionType, "Plugin", StringComparison.OrdinalIgnoreCase))
            {
                LogSignal($"暂不支持的 ConditionType={conditionType}, Method={condition.ConditionMethodName}");
                return false;
            }

            return false;
        }

        /// <summary>按方法名调用内置条件实现。</summary>
        private bool MethodInvoke(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            if (string.IsNullOrWhiteSpace(condition.ConditionMethodName))
            {
                return false;
            }

            if (_eventMethods.TryGetValue(condition.ConditionMethodName, out var handler))
            {
                return handler(snapshot, condition);
            }

            LogSignal($"未注册的条件方法：{condition.ConditionMethodName}");
            return false;
        }

        /// <summary>
        /// 执行任务：MagCar 调用 SendStart/SendStop；其他车型仅打日志。
        /// 通过 ActiveTaskTag 防止同一地标周期内重复下发。
        /// </summary>
        private void ExecuteTask(Car car, FassEventCarSnapshot snapshot, FassEventCarConfig config)
        {
            if (car.tags != null && car.tags.Contains(ActiveTaskTag))
            {
                return;
            }

            var taskType = config.TaskType ?? "Start";
            if (car is MagCar magCar)
            {
                switch (taskType)
                {
                    case "Start":
                        magCar.SendStart((ushort)Math.Round(magCar.th));
                        break;
                    case "Stop":
                        magCar.SendStop(0);
                        break;
                    default:
                        LogTraffic($"车辆[{snapshot.Code}] 收到任务类型[{taskType}]，当前仅显式处理 Start/Stop");
                        break;
                }
            }
            else
            {
                LogTraffic($"车辆[{snapshot.Code}] 非 MagCar，任务类型[{taskType}] 仅记录标签");
            }

            var taskKey = BuildTaskKey(snapshot, config);
            Commons.AddOrUpdateTag(car.tags, ActiveTaskTag, taskKey);
            LogTraffic($"车辆[{snapshot.Code}] 触发事件任务：{taskType} @ node={snapshot.CurrentNodeCode}, state={snapshot.State}");
        }

        /// <summary>生成任务指纹，写入 ActiveTaskTag 的值，便于日志追溯。</summary>
        private static string BuildTaskKey(FassEventCarSnapshot snapshot, FassEventCarConfig config)
        {
            return $"FassEvent:{snapshot.CurrentNodeCode}:{config.TriggerCarState}:{config.TaskType}:{string.Join("|", config.ConditionEvents?.Select(item => item.ConditionMethodName) ?? Array.Empty<string>())}";
        }

        #region 交管条件（节点锁）

        /// <summary>指定节点全部未被其他车辆占用（排除自身）。参数：逗号分隔节点号。</summary>
        private bool NodeAllUnlockedNotCar(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return FassEventNodeHelper.NodeAllUnlockedNotCar(snapshot.Code, SplitArgs(condition.ConditionMethodArgs));
        }

        /// <summary>指定节点全部空闲（含自身锁也计入）。</summary>
        private bool NodeAllUnlocked(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return FassEventNodeHelper.NodeAllUnlocked(SplitArgs(condition.ConditionMethodArgs));
        }

        /// <summary>指定节点中存在被其他车占用的点。</summary>
        private bool NodeAnyLockedNotCar(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return FassEventNodeHelper.NodeAnyLockedNotCar(snapshot.Code, SplitArgs(condition.ConditionMethodArgs));
        }

        /// <summary>
        /// 指定节点存在占用时先 SendStart 再判断（与 FASS NodeAnyLocked 行为一致）。
        /// </summary>
        private bool NodeAnyLocked(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            var car = SimpleCore.SimpleLib.GetCar(snapshot.CarId) as MagCar;
            car?.SendStart((ushort)Math.Round(car.th));
            return FassEventNodeHelper.NodeAnyLocked(SplitArgs(condition.ConditionMethodArgs));
        }

        /// <summary>节点全解锁且路径上无其他运行中车辆。</summary>
        private bool NodeAllUnlockedNotCarNotEndCarState(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return FassEventNodeHelper.NodeAllUnlockedNotCarNotEndCarState(snapshot.Code, "Runing", SplitArgs(condition.ConditionMethodArgs));
        }

        /// <summary>判断指定节点范围是否不存在其他“运行中”车辆（返回 true 表示可以放行）。</summary>
        private bool IsExistRunningStateCar(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            var param = SplitArgs(condition.ConditionMethodArgs);
            LogTraffic($"IsExistRunningStateCar 参数：{condition.ConditionMethodArgs}");
            return !FassEventNodeHelper.ExistsRunningCarOnNodes(snapshot.Code, "Runing", param);
        }

        #endregion

        #region 电量与安全

        /// <summary>
        /// 电量达到阈值方可放行。阈值优先取 ConditionMethodArgs 首参，否则用 Mission.ChargeStartThreshold。
        /// </summary>
        private bool ChargeStart(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            var threshold = _mission.ChargeStartThreshold;
            var configured = SplitArgs(condition.ConditionMethodArgs).FirstOrDefault();
            if (!string.IsNullOrWhiteSpace(configured) &&
                double.TryParse(configured, NumberStyles.Float, CultureInfo.InvariantCulture, out var eventThreshold))
            {
                threshold = eventThreshold;
            }

            var result = snapshot.Charge >= threshold;
            if (result)
            {
                LogSignal($"ChargeStart 车辆[{snapshot.Code}] 电量[{snapshot.Charge}] >= 阈值[{threshold}]");
            }

            return result;
        }

        /// <summary>
        /// 设备安全急停：读 PLC 布尔位，false 表示故障需停车（条件返回 true 以触发 Stop 任务）。
        /// 参数 param[0]：PLC 地址。
        /// </summary>
        private bool EmergencyStop(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return ExecutePlcCondition(snapshot, condition, 1, (client, param) =>
            {
                var allowIn = client.ReadBoolean(param[0]).Value;
                if (!allowIn)
                {
                    LogSignal($"设备安全故障急停：{allowIn}");
                    return true;
                }

                return false;
            });
        }

        /// <summary>
        /// 设备安全恢复：PLC 布尔位为 true 时允许 Start。
        /// </summary>
        private bool EmergencyStart(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return ExecutePlcCondition(snapshot, condition, 1, (client, param) =>
            {
                var allowIn = client.ReadBoolean(param[0]).Value;
                if (allowIn)
                {
                    LogSignal($"设备安全恢复放行：{allowIn}");
                    return true;
                }

                return false;
            });
        }

        #endregion

        #region ME11 下料站 PLC 交互

        /// <summary>
        /// 清除站点到位与离开中信号。
        /// 参数：param[0] 到位信号地址，param[1] 离开中信号地址。
        /// </summary>
        private bool ClearStation(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            var context = BuildStationLogContext(nameof(ClearStation), snapshot, condition);
            LogSignal($"{context} 开始清除站点到位/离开中信号");
            if (!_mission.IsEnableMEll)
            {
                LogSignal($"车辆[{snapshot.Code}] ME11 未启用，直接返回 true");
                return true;
            }

            return ExecutePlcCondition(snapshot, condition, 2, (client, param) =>
            {
                var afterClear = WriteAndRead(client, param[0], false, "清除到位信号", context);
                WriteStationSignal(client, param[1], false, "清除离开中信号", context);
                var leavingClear = client.ReadBoolean(param[1]).Value;
                var result = !afterClear && !leavingClear;
                LogSignal($"{context} 清除站点信号结束，返回[{result}]");
                return result;
            });
        }

        /// <summary>
        /// 请求进入工位：读“请求进入”，为 true 时写“正在进入中”，并以进入中信号作为放行条件结果。
        /// 参数：param[0] 请求进入，param[1] 正在进入中。
        /// </summary>
        private bool RequestStation(FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            var context = BuildStationLogContext(nameof(RequestStation), snapshot, condition);
            LogSignal($"{context} 开始请求进入信号判断");
            if (!_mission.IsEnableMEll)
            {
                LogSignal($"车辆[{snapshot.Code}] ME11 未启用，直接返回 true");
                return true;
            }

            return ExecutePlcCondition(snapshot, condition, 2, (client, param) =>
            {
                var requestIn = ReadStationSignal(client, param[0], "请求进入", context);
                if (requestIn)
                {
                    WriteStationSignal(client, param[1], true, "正在进入中", context);
                }

                var result = ReadStationSignal(client, param[1], "正在进入中", context);
                LogSignal($"{context} 请求进入判断结束，返回[{result}]");
                return result;
            });
        }

        /// <summary>
        /// 到位与允许离开交互（ME11 下料核心逻辑）。
        /// <para>
        /// 参数：param[0] 到位，param[1] 允许离开，param[2] 正在进入中，param[3] 正在离开中。
        /// ME11 车型：气缸伸出(Read3&amp;Read5)后写到位；读到允许离开后切换为放行车型。
        /// 放行车型：气缸收回(Read4&amp;Read6)后写离开中、清除到位。
        /// </para>
        /// </summary>
    

        /// <summary>将车辆 fields["CarModel"] 切换为放行车型，供后续触发器匹配。</summary>
        private void SaveCarModel(int carId, string carModel, string reason)
        {
            var car = SimpleCore.SimpleLib.GetCar(carId) as Car;
            if (car == null)
            {
                return;
            }

            car.fields ??= new Dictionary<string, string>();
            if (string.Equals(FassEventCarSnapshotFactory.GetCarModel(car), carModel, StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            car.fields["CarModel"] = carModel;
            LogSignal($"{reason}：车辆[{FassEventCarSnapshotFactory.GetCarCode(car)}] 车型切换为 [{carModel}]");
        }

        #endregion

        #region PLC 与工具方法

        /// <summary>在 PLC 锁内打开连接、执行读写、关闭连接。</summary>
        private bool ExecutePlcCondition(
            FassEventCarSnapshot snapshot,
            FassConditionEventConfig condition,
            int minArgs,
            Func<SiemensClient, string[], bool> action)
        {
            if (!TryGetConditionArgs(condition, minArgs, out var param))
            {
                return false;
            }

            lock (_plcLock)
            {
                SiemensClient client = null;
                try
                {
                    client = CreatePlcClient();
                    client.Open();
                    return action(client, param);
                }
                catch (Exception ex)
                {
                    LogSignalError(ex, "交互站点报错");
                    return false;
                }
                finally
                {
                    client?.Close();
                }
            }
        }

        /// <summary>根据 Mission 配置创建西门子 PLC 客户端。</summary>
        private SiemensClient CreatePlcClient()
        {
            var version = ParsePlcVersion(_mission.PlcVersion);
            return new SiemensClient(version, _mission.PlcIpAddress, _mission.PlcPort, 0);
        }

        private static SiemensVersion ParsePlcVersion(string version)
        {
            if (string.IsNullOrWhiteSpace(version))
            {
                return SiemensVersion.S7_1500;
            }

            return Enum.TryParse(version, true, out SiemensVersion parsed) ? parsed : SiemensVersion.S7_1500;
        }

        /// <summary>拼接站点交互日志上下文，便于现场对照 PLC 地址排查。</summary>
        private string BuildStationLogContext(string methodName, FassEventCarSnapshot snapshot, FassConditionEventConfig condition)
        {
            return $"{methodName} 车辆[{snapshot.Code}] 状态[{snapshot.State}] 当前地标[{snapshot.CurrentNodeCode}] 下一地标[{snapshot.NextNodeCode}] 车型[{snapshot.CarModel}] 参数[{condition.ConditionMethodArgs}]";
        }

        private bool ReadStationSignal(SiemensClient client, string address, string signalName, string context)
        {
            var value = client.ReadBoolean(address).Value;
            LogSignal($"{context} 读取信号[{signalName}] 地址[{address}] 值[{value}]");
            return value;
        }

        private void WriteStationSignal(SiemensClient client, string address, bool value, string signalName, string context)
        {
            LogSignal($"{context} 写入信号[{signalName}] 地址[{address}] 值[{value}]");
            client.Write(address, value);
            var readBackValue = client.ReadBoolean(address).Value;
            LogSignal($"{context} 回读信号[{signalName}] 地址[{address}] 值[{readBackValue}]");
        }

        private bool WriteAndRead(SiemensClient client, string address, bool value, string signalName, string context)
        {
            WriteStationSignal(client, address, value, signalName, context);
            return client.ReadBoolean(address).Value;
        }

        /// <summary>校验条件参数个数是否满足 PLC 方法要求。</summary>
        private static bool TryGetConditionArgs(FassConditionEventConfig condition, int minLength, out string[] args)
        {
            args = SplitArgs(condition.ConditionMethodArgs);
            return args.Length >= minLength;
        }

        /// <summary>将逗号分隔的配置参数字符串拆分为数组。</summary>
        private static string[] SplitArgs(string args)
        {
            if (string.IsNullOrWhiteSpace(args))
            {
                return Array.Empty<string>();
            }

            return args.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(item => item.Trim())
                .ToArray();
        }

        /// <summary>
        /// CSV 过滤器：filter 为空则通过；否则 value 必须等于 filter 中某项（忽略大小写）。
        /// 用于 TriggerCarState 等多值匹配，如 "Stopping,Charging"。
        /// </summary>
        private static bool MatchesCsvFilter(string filter, string value)
        {
            if (string.IsNullOrWhiteSpace(filter))
            {
                return true;
            }

            if (string.IsNullOrWhiteSpace(value))
            {
                return false;
            }

            return filter.Split(',').Select(item => item.Trim()).Any(item => string.Equals(item, value, StringComparison.OrdinalIgnoreCase));
        }

        private void LogTraffic(string message) => Diagnosis.Post(message, "Fass交管", true);

        private void LogSignal(string message) => Diagnosis.Post(message, "Fass信号交互", true);

        private void LogSignalError(Exception ex, string message) =>
            Diagnosis.Post($"{message}: {ExceptionFormatter.FormatEx(ex)}", "Fass信号交互", true);

        #endregion
    }

    /// <summary>从磁盘加载 EventCar JSON 配置数组。</summary>
    internal static class FassEventConfigLoader
    {
        /// <summary>
        /// 读取并反序列化配置文件。
        /// </summary>
        /// <param name="configPath">JSON 文件路径。</param>
        /// <returns>事件配置列表；文件内容为空数组时返回空列表。</returns>
        /// <exception cref="FileNotFoundException">文件不存在时抛出。</exception>
        public static List<FassEventCarConfig> Load(string configPath)
        {
            if (string.IsNullOrWhiteSpace(configPath) || !File.Exists(configPath))
            {
                throw new FileNotFoundException($"未找到 FASS 车辆事件配置文件：{configPath}");
            }

            var json = File.ReadAllText(configPath);
            return Newtonsoft.Json.JsonConvert.DeserializeObject<List<FassEventCarConfig>>(json)
                ?? new List<FassEventCarConfig>();
        }
    }
}
