using Aitex.Common.Util;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using DictActionsPerLight = System.Collections.Generic.Dictionary<MECF.Framework.Common.Device.Bases.STLightTypes, MECF.Framework.Common.Device.Bases.STAction>;
using DictEvent = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<MECF.Framework.Common.Device.Bases.STAction>>;

namespace MECF.Framework.Common.Device.Bases
{
    /// <summary>
    /// 信号塔对象。
    /// </summary>
    public class SignalTowerBase : BaseDevice, IDevice
    {
        #region Variables

        /// <summary>
        /// 系统保留的工作模式配置项，用于工艺结束后蜂鸣器发出提示音。
        /// </summary>
        protected const string KEY_PATTERN_JOB_DONE = "JobDone";

        /// <summary>
        /// 信号灯字典。
        /// </summary>
        private readonly Dictionary<STLightTypes, SignalTowerLightBase> _dictStLights;

        /// <summary>
        /// 是否关闭蜂鸣器输出。
        /// <value>True：蜂鸣器被手动关闭，满足事件条件也不要打开蜂鸣器。</value>
        /// <value>False：根据当前系统状态和配置事件自动输出蜂鸣器状态。</value>
        /// </summary>
        private bool _switchBuzzerOff;

        /// <summary>
        /// 信号塔事件字典，从配置文件中读取。
        /// <remarks>
        /// 字典的Key表示事件名称，对应STEvent配置文件中的name属性。
        /// </remarks>
        /// <br/>
        /// <remarks>
        /// 注意：操作该字典时需要加锁，因为当前对象支持实时监测配置文件并重载配置文件的改动；配置文件
        /// 内容改动后，会重新创建该字典，此时有可能Monitor()方法正在使用此字典。
        /// </remarks>
        /// </summary>
        private DictEvent _dictPreDefinedEvents;

        /// <summary>
        /// 信号塔扩展事件字典。
        /// <remarks>
        /// 除STEvents配置中预设的事件外，还有一类事件通常由RT触发，这类事件也需要参与三色灯输出状态判断。
        /// </remarks>
        /// </summary>
        private readonly DictEvent _dictDynamicSTLightActions;

        /// <summary>
        /// 信号塔组件动作字典。
        /// </summary>
        private DictActionsPerLight _dictSTLightActions;

        /// <summary>
        /// 上一次Monitor周期触发的事件列表。
        /// 用于下一次Monitor周期判断是否有新的事件产生，已解决蜂鸣器被手动关闭后，如果未按下Reset，则下次新事件产生时，无法响蜂鸣器的问题。
        /// </summary>
        private readonly List<string> _lastEventsWithBuzzer = [];

        /// <summary>
        /// STEvents配置文件解析对象。
        /// </summary>
        private STEvents _eventsFileLoader;

        #endregion

        #region Constructors

        /// <summary>
        /// 构建信号塔对象的实例。
        /// </summary>
        /// <param name="module">当前模组名称。</param>
        /// <param name="node">设备配置文件。</param>
        /// <param name="ioModule">所属Module的名称。</param>
        public SignalTowerBase(string module, XmlElement node, string ioModule = "")
            : base(module, node, ioModule)
        {
            _dictSTLightActions = new();
            _dictStLights = new Dictionary<STLightTypes, SignalTowerLightBase>();
            _dictDynamicSTLightActions = new ();
            
            var doRedLight = ParseDoNode("doRed", node, ioModule);
            var doYellowLight = ParseDoNode("doYellow", node, ioModule);
            var doGreenLight = ParseDoNode("doGreen", node, ioModule);
            var doBlueLight = ParseDoNode("doBlue", node, ioModule);
            var doWhiteLight = ParseDoNode("doWhite", node, ioModule);
            var doBuzzer = ParseDoNode("doBuzzer", node, ioModule);
            var doBuzzer1 = ParseDoNode("doBuzzer1", node, ioModule);
            var doBuzzer2 = ParseDoNode("doBuzzer2", node, ioModule);
            var doBuzzer3 = ParseDoNode("doBuzzer3", node, ioModule);
            var doBuzzer4 = ParseDoNode("doBuzzer4", node, ioModule);
            var doBuzzer5 = ParseDoNode("doBuzzer5", node, ioModule);
            var aoBuzzerBlinkFreq = ParseAoNode("aoBuzzerBlinkFreq", node, ioModule);
            var eventFile = node.GetAttribute("eventFile");

            // 红、黄、绿、蜂鸣器是必须定义的元件。
            Debug.Assert(doRedLight != null, "DO of RedLight not defined");
            Debug.Assert(doYellowLight != null, "DO of YellowLight not defined");
            Debug.Assert(doGreenLight != null, "DO of GreenLight not defined");
            Debug.Assert(doBuzzer != null, "DO of Buzzer not defined");

            // 创建三色灯控制元件。
            CreateSTLight(STLightTypes.Red, doRedLight);
            CreateSTLight(STLightTypes.Yellow, doYellowLight);
            CreateSTLight(STLightTypes.Green, doGreenLight);
            CreateSTLight(STLightTypes.Blue, doBlueLight);
            CreateSTLight(STLightTypes.White, doWhiteLight);
            CreateSTLight(STLightTypes.Buzzer, doBuzzer, aoBuzzerBlinkFreq);
            CreateSTLight(STLightTypes.Buzzer1, doBuzzer1);
            CreateSTLight(STLightTypes.Buzzer2, doBuzzer2);
            CreateSTLight(STLightTypes.Buzzer3, doBuzzer3);
            CreateSTLight(STLightTypes.Buzzer4, doBuzzer4);
            CreateSTLight(STLightTypes.Buzzer5, doBuzzer5);

            // 添加文件到监视器，当文件内容发生变化时重新加载配置。
            var fullFn = PathManager.GetCfgDir() + eventFile;
            FileSystemWatcherManager.Instance.Register(fullFn, fn =>
            {
                ParseSTEvent(fn);
            });

            //解析三色灯Event
            ParseSTEvent(fullFn);
        }

        #endregion

        #region Properties

        /// <summary>
        /// 返回信号塔当前状态数据集。
        /// <remarks>该属性用于RT到UI间的数据传递。</remarks>
        /// </summary>
        public AITSignalTowerData DeviceData => new AITSignalTowerData
        {
            DeviceName = Name,
            DeviceSchematicId = DeviceID,
            DisplayName = Display,
            IsGreenLightOn = GetSignalTowerPartValue(STLightTypes.Green),
            IsRedLightOn = GetSignalTowerPartValue(STLightTypes.Red),
            IsYellowLightOn = GetSignalTowerPartValue(STLightTypes.Yellow),
            IsBlueLightOn = GetSignalTowerPartValue(STLightTypes.Blue),
            IsWhiteLightOn = GetSignalTowerPartValue(STLightTypes.White),
            IsBuzzerOn = GetSignalTowerPartValue(STLightTypes.Buzzer),
            IsBuzzer1On = GetSignalTowerPartValue(STLightTypes.Buzzer1),
            IsBuzzer2On = GetSignalTowerPartValue(STLightTypes.Buzzer2),
            IsBuzzer3On = GetSignalTowerPartValue(STLightTypes.Buzzer3),
            IsBuzzer4On = GetSignalTowerPartValue(STLightTypes.Buzzer4),
            IsBuzzer5On = GetSignalTowerPartValue(STLightTypes.Buzzer5),
            GreenLightEvent = _dictStLights[STLightTypes.Green]?.Action?.EventName ?? "",
            YellowLightEvent = _dictStLights[STLightTypes.Yellow]?.Action?.EventName ?? "",
            RedLightEvent = _dictStLights[STLightTypes.Red]?.Action?.EventName ?? "",
            BuzzerEvent = _dictStLights[STLightTypes.Buzzer]?.Action?.EventName ?? ""
        };

        #endregion

        #region Methods

        /// <summary>
        /// 创建一个信号塔元件，并添加到字典中。
        /// </summary>
        /// <param name="light">信号塔元件类型，请参考<see cref="STLightTypes"/>。</param>
        /// <param name="doSw">控制元件开关的DO。</param>
        /// <param name="aoBlinkFreq">控制Blink频率的AO。</param>
        private void CreateSTLight(STLightTypes light, DOAccessor doSw, AOAccessor aoBlinkFreq = null)
        {
            if (doSw != null)
                _dictStLights.Add(light, new SignalTowerLightBase(Module, light, doSw, aoBlinkFreq));
        }

        /// <summary>
        /// 从指定的配置文件中解析信号塔事件。
        /// </summary>
        /// <param name="fileName">包含完整路径的配置文件文件名。</param>
        /// <returns></returns>
        private bool ParseSTEvent(string fileName)
        {
            try
            {
                if (!File.Exists(fileName))
                {
                    LOG.Error($"Unable to find signal tower events config file {fileName}.");
                    return false;
                }

                _eventsFileLoader = CustomXmlSerializer.Deserialize<STEvents>(new FileInfo(fileName));
                _eventsFileLoader.ParseEvents(_dictStLights, out var events);
                if (events == null)
                    LOG.Error("Unable to parse the signal tower events from config file.");

                lock (SyncRoot)
                {
                    _dictPreDefinedEvents = events;
                    return _dictPreDefinedEvents != null;
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.ToString());
                return false;
            }
        }
        
        /// <summary>
        /// 初始化信号塔对象实例。
        /// </summary>
        /// <remarks>
        /// 注册SwitchOffBuzzer操作和DeviceData数据。
        /// </remarks>
        /// <returns></returns>
        public bool Initialize()
        {
            DATA.Subscribe(Module + "." + Name + ".DeviceData", () => DeviceData);

            return true;
        }

        /// <summary>
        /// 复位信号塔状态及其各个组件。
        /// </summary>
        public void Reset()
        {
            _switchBuzzerOff = false;
            lock (SyncRoot)
            {
                _dictDynamicSTLightActions?.Clear();
            }

            foreach (var light in _dictStLights.Values)
                light.Reset();
        }

        /// <summary>
        /// 终止信号塔对象实例。
        /// </summary>
        public void Terminate()
        {
            foreach (var light in _dictStLights.Values)
                light.Terminate();
        }


        /// <summary>
        /// 周期性扫描信号塔以执行后台任务。
        /// </summary>
        protected override void HandleMonitor()
        {
            // 遍历所有预设的事件，决定信号塔各元件的输出状态。
            MonitorEvents(out var buzzerOnEvents);

            // 判断是否有新的Buzzer相关事件产生，如果有，需要复位_switchBuzzerOff状态，以重新使能蜂鸣器，解决蜂鸣器被手动关闭后，如果不按Reset，则无法重启启用的问题。
            var buzzerOnEventArray = buzzerOnEvents as string[] ?? buzzerOnEvents.ToArray();
            var newBuzzerOnEvents = _lastEventsWithBuzzer.Except(buzzerOnEventArray);
            if (newBuzzerOnEvents.Any())
            {
                _lastEventsWithBuzzer.Clear();
                _lastEventsWithBuzzer.AddRange(buzzerOnEventArray);
                _switchBuzzerOff = false;
            }

            // 分配每个信号灯的动作。
            foreach (var kvp in _dictSTLightActions)
            {
                var action = kvp.Value;

                if (action?.Light == null)
                    continue;

                // 创建动作副本，因为后续可能根据_switchBuzzerOff调整输出状态，避免覆盖原配置。
                var cloned = (STAction)action.Clone();

                // 如果蜂鸣器被强制关闭，则将待执行动作中的状态修改为Off
                if (action.Light.IsBuzzer && _switchBuzzerOff)
                    cloned.Output = SignalTowerActions.Off;

                action.Light.SetAction(cloned);
            }

            // 扫描信号塔组件状态
            foreach (var light in _dictStLights.Values)
            {
                if(light == null) 
                    continue;
                
                // 如果是蜂鸣器，并且用户按了静音，则关闭蜂鸣器
                //if (light.IsBuzzer && _switchBuzzerOff)
                //    light.Action.Output = SignalTowerActions.Off;

                light.Monitor();

                // remove the cycle done action from dynamic STEvent dictionary
                var currAction = light.Action;
                if (currAction is { IsCycleDone: true } 
                    && _dictDynamicSTLightActions.TryGetValue(currAction.EventName, out var actions))
                {
                    for (var i = actions.Count - 1; i >= 0; i--)
                    {
                        if (actions[i].LightType == light.Type)
                            actions.RemoveAt(i);
                    }
                }
            }
        }

        /// <summary>
        /// 当Wafer回到Cassette后，打开蜂鸣器以指示ProcessJob结束。
        /// </summary>
        /// <returns></returns>
        public bool AlertJobDone()
        {
            SignalTowerLightBase targetBuzzer = null;
            STBlinkPattern blinkPattern = null;

            // 从系统配置获取JobDone模式
            var pattern = SC.SafeGetStringValue("System.SignalTower.JobDoneBuzzerPattern", "--..........");
            var cycle = SC.SafeGetValue("System.SignalTower.JobDoneBuzzerCycle", 10);
            var priority = SC.SafeGetValue("System.SignalTower.JobDoneBuzzerPriority", -1);

            if (!Regex.IsMatch(pattern, @"^[-.]+$"))
            {
                // 判断Pattern中是否仅包含-和.，如果有其它非法字符，则优先使用STEvent.xml中定义的内容，如果仍然找不到或格式非法，则使用默认值‘--..........’。

                LOG.Error($"{UniqueName} Format of JobDone Pattern in system config '{pattern}' is error");

                // 读取STEvents配置文件中的JobDone模式的配置。
                var patternInXmlFile = _eventsFileLoader.PatternsSettings.FirstOrDefault(x => x.Name == KEY_PATTERN_JOB_DONE);
                if (patternInXmlFile != null && Regex.IsMatch(pattern, @"^[-.]+$"))
                {
                    pattern = patternInXmlFile.Pattern;
                    LOG.Warning($"{UniqueName} JobDone Pattern is replaced by the value defined in STEvent file which is '{pattern}'");
                }
                else
                {
                    pattern = "--..........";
                    LOG.Warning($"{UniqueName} No available pattern for JobDone alert, fallback to the default value '--..........'");
                }
            }

            LOG.Info($"{UniqueName} JobDone alert settings: Pattern='{pattern}', Cycle={cycle}, Priority={priority}");

            blinkPattern = new STBlinkPattern(pattern, priority, cycle);
            _dictStLights.TryGetValue(STLightTypes.Buzzer, out var buzzer);
            targetBuzzer = buzzer;
            if (targetBuzzer == null)
            {
                LOG.Error($"{UniqueName} Buzzer object is not existed");
                return false;
            }

             /*if (alertPattern != null)
            {
                // 解析配置中的Buzzer，如果未指定Buzzer，或指定为除Buzzer以外的信号灯，则默认使用Buzzer。
                var targetLight = alertPattern.Part;
                if (Enum.TryParse(targetLight, out STLightTypes lightType)
                    && _dictStLights.TryGetValue(lightType, out var buzzer)
                    && buzzer.IsBuzzer)
                    targetBuzzer = buzzer;

                blinkPattern = new STBlinkPattern(alertPattern.Pattern, priority: alertPattern.Priority, cycle: alertPattern.Cycles);
            }
           else
            {
                // 没找到JobDone的工作模式配置，生成默认配置
                blinkPattern = STBlinkPattern.GetJobDonePattern();
                LOG.Warning($"Unable to find pre-defined pattern for {KEY_PATTERN_JOB_DONE}");
            }*/

            var buzzerAction = new STAction(KEY_PATTERN_JOB_DONE, targetBuzzer, SignalTowerActions.Customized,
                blinkPattern);
            CreateDynamicEvent(KEY_PATTERN_JOB_DONE, [buzzerAction]);
            return true;
        }

        /// <summary>
        /// 打开或关闭蜂鸣器。
        /// </summary>
        /// <param name="isOff"></param>
        /// <returns></returns>
        public bool SwitchOffBuzzer(bool isOff)
        {
            _switchBuzzerOff = isOff;
            return true;
        }

        /// <summary>
        /// 获取优先级更高的STAction。
        /// <remarks>
        /// 根据<see cref="STAction.Output"/>的优先级决定执行的动作。
        /// <br/>
        /// 此属性的数值越小，表示优先级越高。
        /// </remarks>
        /// </summary>
        /// <param name="currentAction">当前输出状态。</param>
        /// <param name="nextAction">期望的输出状态。</param>
        /// <returns>合并后的信号灯输出状态。</returns>
        private STAction PickPriorAction(STAction currentAction, STAction nextAction)
        {
            if (currentAction == null)
                return nextAction;
            if (nextAction == null)
                return currentAction;

            // 获取当前动作的优先级
            var curPrior = currentAction.Output == SignalTowerActions.Customized
                ? currentAction.BlinkPattern.Priority
                : (int)currentAction.Output;

            // 获取下一个动作的优先级
            var nextPrior = nextAction.Output == SignalTowerActions.Customized
                ? nextAction.BlinkPattern.Priority
                : (int)nextAction.Output;


            return curPrior < nextPrior ? currentAction : nextAction;
        }

        /// <summary>
        /// 获取指定信号塔元件的输出状态。
        /// </summary>
        /// <param name="light"></param>
        /// <returns></returns>
        private bool  GetSignalTowerPartValue(STLightTypes light)
        {
            if (_dictStLights.TryGetValue(light, out var part))
                return part.GetValue();

            return false;
        }

        /// <summary>
        /// 从RT拉取已发生的STEvent列表。
        /// </summary>
        /// <returns></returns>
        private static DictEvent PollRaisedEvents(DictEvent dicEvents)
        {
            if (dicEvents == null)
                return new();

            var events = dicEvents.Keys.ToList();
            var data = DATA.PollData(events);
            var raisedEvents = data.Where(x => x.Value is true).Select(x => x.Key).ToList();

            return dicEvents.Where(x => raisedEvents.Contains(x.Key)).ToDictionary(x => x.Key, v => v.Value);
        }

        /// <summary>
        /// 监视STEvent.xml中定义的事件和RT创建的DynamicEvents，并返回Buzzer相关的事件列表。
        /// </summary>
        /// <param name="eventsWithBuzzerOn">
        /// Buzzer相关的事件列表。
        /// </param>
        private void MonitorEvents(out IEnumerable<string> eventsWithBuzzerOn)
        {
            lock (SyncRoot)
            {
                // Clear previous actions
                _dictSTLightActions.Clear();

                // Poll raised events of RT
                var raisedEvents = PollRaisedEvents(_dictPreDefinedEvents);

                // Create dictionary '_dictSTLightActions'
                AssignSTActions(raisedEvents);
                AssignSTActions(_dictDynamicSTLightActions);

                // Get a list of events related to turning on a buzzer
                var buzzerOnEv1 = GetBuzzerOnEvents(raisedEvents).ToArray();
                var buzzerOnEv2 = GetBuzzerOnEvents(_dictDynamicSTLightActions).ToArray();

                eventsWithBuzzerOn = buzzerOnEv1.Concat(buzzerOnEv2.Except(buzzerOnEv1));
            }
        }

        /// <summary>
        /// 根据已发生的STEvent决定各个信号灯的动作。
        /// </summary>
        /// <param name="raisedEvents"></param>
        private void AssignSTActions(DictEvent raisedEvents)
        {
            foreach (var stEvent in raisedEvents)
            {
                foreach (var action in stEvent.Value)
                {
                    // Maybe the target light of the action is not defined
                    if (!_dictStLights.ContainsKey(action.LightType))
                        continue;

                    // Make it easier to access dictionaries using the key
                    var light = action.LightType;

                    // Determine the action of light according to the event raised
                    if (!_dictSTLightActions.TryGetValue(light, out var oldAction))
                        _dictSTLightActions.Add(light, action);
                    else
                        _dictSTLightActions[light] = PickPriorAction(oldAction, action);
                }
            }
        }

        /// <summary>
        /// 获取需要打开Buzzer的事件的名称。
        /// </summary>
        /// <param name="events"></param>
        /// <returns></returns>
        private IEnumerable<string> GetBuzzerOnEvents(DictEvent events)
        {
            // create a list for the events operating the buzzer
            var buzzerOnEvents = events
                .Where(x => x.Value
                    .Any(v => v.Light.IsBuzzer && v.Output != SignalTowerActions.Off))
                .Select(x => x.Key);

            return buzzerOnEvents;
        }

        /// <summary>
        /// 创建一个动态RT事件，以驱动指定的信号塔组件。
        /// <remarks>
        /// 自动创建Guid作为事件的Key，以和STEvent配置字典的格式保持一致，以为Monitor方法中需要同时对这两个字典处理；格式的统一有助于统一处理任务的逻辑。
        /// </remarks>
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="actions">该事件执行的动作列表。
        /// <remarks>
        /// 列表的每一个元素对应一个信号塔组件需执行的动作。
        /// </remarks>
        /// </param>
        private void CreateDynamicEvent(string eventName, List<STAction> actions)
        {
            // 确保同一个Event只创建一次。
            lock (SyncRoot)
            {
                if (_dictDynamicSTLightActions.ContainsKey(eventName))
                    _dictDynamicSTLightActions.Remove(eventName);

                _dictDynamicSTLightActions[eventName] = actions;

                // 如果存在Buzzer相关的事件，则强制取消Buzzer静音。
                if (actions.Any(x => x.Light.IsBuzzer))
                    SwitchOffBuzzer(false);
            }
        }

        #endregion

    }



}
