using Common;
using Common.Models;
using CommunityToolkit.Mvvm.Messaging;
using MegaRobo.C00225155.DataAccess;
using MegaRobo.C00225155.Entities;
using MegaRobo.C00225155.Entities.Entity_DB;
using MegaRobo.C00225155.Entities.ToWeb;
using MegaRobo.Contract;
using MegaRobo.ControlDevices;
using MegaRobo.ControlDevices.Abstractions;
using MegaRobo.ControlDevices.Models;
using MegaRobo.Entities;
using MegaRobo.Logger;
using MegaRobo.PipetteTool.HamiltonConsole.PipetteDevices.HamiltonDevices;
using MegaRobo.Utility.Files;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace MegaRobo.C00225155.AppServer.ExecuteWorks;

public abstract class StationServiceBase : ModbusWorkServiceBase
{
    #region 服务字段
    protected WorkService workService { get; set; }
    protected AppConfigService appConfigService;
   
    /// <summary>
    /// PLC通讯的ModbusClient
    /// </summary>
    protected IModbusClientExtend ModbusClient;

    /// <summary>
    /// PLC 名称
    /// </summary>
    protected DeviceNames PlcName;

    protected IDataAccessService dataAccessService;

    protected IDictionary<string, string> PipetteErrorDic = new Dictionary<string, string>();

    //protected StationProperty StationProp = new StationProperty();
    #endregion

    #region Field\Property
    /// <summary>
    /// 从数据库中加载的所有PLC报警点位
    /// </summary>
    protected IList<PlcPoint> WarnPointList { get; set; }

    /// <summary>
    /// 从CSV文件中加载的所有报警点位、报警信息
    /// </summary>
    protected List<PLCErrorPoint> PLCErrorInfoList { get; set; } = new List<PLCErrorPoint>();

    /// <summary>
    /// 当前报警信息，触发事件
    /// </summary>
    protected List<PLCErrorPoint> PLCErrorLists { get; set; } = new List<PLCErrorPoint>();

    /// <summary>
    ///扫描PLC 错误信息集合事件
    /// </summary>
    public event EventHandler<List<PLCErrorPoint>> OnScanPlcErrorListEvent;

    protected bool Runing = false;

    protected string stationName = string.Empty;

    #endregion

    protected StationServiceBase(ICoreService coreService, WorkService workService, DeviceNames plcName, string stationName)
    {
        this.PlcName = plcName;
        this.stationName = stationName;
        this.CoreService = coreService;
        this.workService = workService;// 关联上级WorkService（便于跨工站交互）
        appConfigService = this.CoreService.GetServiceInstance<AppConfigService>();// 配置服务
        dataAccessService = this.CoreService.GetServiceInstance<IDataAccessService>();// 数据访问服务
    }

    protected override void LoadServices()
    {
        this.ModbusClient = this.CoreService.GetServiceInstance<IModbusClientExtend>(this.PlcName.ToString());
        if (this.ModbusClient is not null)
        {
            this.ModbusClient.ScannedEvent += this.ModbusClientBaseOnScannedEvent;
            this.ModbusClient.PulseTickAction += this.OnPulseTick;
        }
    }

    protected override void LoadDatas()
    {
        base.LoadDatas();
        RegisterPipetteErrorCode();
    }

    protected override async void RegisterPoints()
    {
        //转移至 StartupService 统一注册
    }

    protected void RegisterPipetteErrorCode()
    {
        PipetteErrorDic = new Dictionary<string, string>()
        {
            { "00", "执行成功" },
            { "20", "硬件问题，请联系Hamilton"},
            { "30", "未知命令，请参考命令表"},
            { "31", "未知参数，请参考命令表"},
            { "32", "发送的参数值超出预定范围，请参考命令表"},
            { "35", "电源电压超出运行范围,请确保电源电压是48V+-5%"},
            { "36", "关闭紧急停止"},
            { "38", "空液体类型"},
            { "39", "液体类型写保护"},
            { "40", "一次只能发送一个命令"},
            { "50", "Z轴初始化失败,硬件问题，请联系Hamilton"},
            { "51", "请初始化泵驱动"},
            { "52", "泵驱动初始化失败,硬件问题，请联系Hamilton"},
            { "53", "tip 头容量不够，无法吸入ai 值得液体，改变ai值或更改tip 头"},
            { "54", "达到泵的最大值"},
            { "55", "吸液体积校验失败，吸液量不满足当前Tip头的最小值"},
            { "56", "选择的液体类型要求用导电tip 头，请确认液体类型和tip 头类型编号一致"},
            { "57", "确定液体类型一致和tip 头类型编号"},
            { "60", "ZI初始化失败，硬件未工作，请联系Hamilton"},
            { "61", "Z轴驱动初始化失败"},
            { "62", "Z 轴驱动移动错误 硬件未工作，请联系Hamilton"},
            { "63", "移动碰触到试管底部"},
            { "64", "Z 轴，驱动达不到gy(要移动到的位置) 值，请检查参数"},
            { "65", "Z 轴，驱动达不到te(转移高度)值，请检查参数"},
            { "66", "Z 轴，驱动达不到ce(容器底部高度) 值，请检查参数"},
            { "67", "Z 轴，驱动达不到cf(液面的高度) 值，请检查参数"},
            { "68", "Z 轴，驱动达不到zp(开始探测液面的位置) 值，请检查参数"},
            { "69", "Z 轴，驱动达不到tr(丢弃Tip头位置) 值，请检查参数"},
            { "70", "在zp 和ce 两个值之间未检测到液面，请检查参数设置"},
            { "71", "液体不足"},
            { "72", "压力传感器自动校准失效,硬件未工作，请联系Hamilton"},
            { "74", "提前检测到液面"},
            { "75", "未取到tip 头"},
            { "76", "tip 头已经取到"},
            { "80", "吸液过程中检测到堵塞"},
            { "81", "吸液过程中检测到吸空"},
            { "82", "吸液过程中检测到气泡"},
            { "83", "分配过程中检测到堵塞"},
            { "84", "分配过程中检测到气泡"},
            { "85", "未与数字电平通信上，硬件问题，请联系Hamilton"},
        };
    }

    protected override void LoadPlcWarnInfoSetting()
    {
        base.LoadPlcWarnInfoSetting();
        this.PLCErrorInfoList.Clear();
        WarnPointList = new List<PlcPoint>();
        string filePath = string.Empty;
        if (this.PlcName == DeviceNames.Plc1)//投料站
        {
            filePath = "DataBox\\PlcWarnSetting_Dose.csv";
        }
        else if (this.PlcName.Equals(DeviceNames.Plc2)) //反应站
        {
            filePath = "DataBox\\PlcWarnSetting_React.csv";
        }
        string[] lines = File.ReadAllLines(filePath, System.Text.Encoding.GetEncoding("utf-8"));

        foreach (string line in lines)
        {
            string key = string.Empty;
            string[] columns = line.Split(',');
            if (columns.Length != 2)
            {
                continue;
            }

            key = columns[0].Replace("MX", "");
            string value = columns[1];
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) continue;
            if (!double.TryParse(key, out double _point)) continue;

            PLCErrorPoint point = new PLCErrorPoint() { ErrorAddress = key, ErrorInfo = value };
            this.PLCErrorInfoList.Add(point);
        }
        var alladdress = PLCErrorInfoList.Select(x => x.ErrorAddress.Split(".")[0]).Distinct().ToList();
        var client = this.CoreService.GetServiceInstance<IModbusClientExtend>("Plc1");
        foreach (var addr in alladdress)
        {
            client.Register<System.Drawing.Point>(ushort.Parse(addr), $"报警点位-{addr}", FunType.ReadHoldingRegisters);
            PlcPoint plcPoint = new PlcPoint()
            {
                 Address = ushort.Parse(addr), Descr = $"报警点位-{addr}", FunType = FunType.ReadHoldingRegisters
            };
            WarnPointList.Add(plcPoint);
        }
        //this.WarnPointList = 
        //this.WarnPointList = this.dataAccessService.LoadEntitiesAsync<PlcPoint>(x => x.Name == this.PlcName.ToString() && x.Level == 2).Result;
        this.Runing = true;  
    }

    protected string GetMethodName([CallerMemberName] string memberName = "")
    {
        return memberName;
    }

    //protected virtual async Task InitPreAsync()
    //{
    //    await Task.Delay(0);
    //}

    #region PLC读取/写入值操作

    #endregion

    private ushort _lastTickValue = 1; //先缓存, 尽量减少通讯次数
    protected override void OnPulseTick()
    {
        var currValue = (ushort)(DateTime.Now.Second % 2);  //间隔两秒给一次心跳
        if (currValue == 0)
        {
            //this._lastTickValue = currValue;
            this.ModbusClient.Command.WriteValue<ushort>(PlcPoints_MaterialDose.W_PCHeartPluse[(ushort)this.PlcName], 1);
        }
    }

    #region ModBus

    protected async void LoadPlcAlarmInfoSetting()
    {
        //注册提示点位
        // this.WarnPointList  = await this.DataAccessService.LoadEntitiesAsync<PlcPoint>(x =>
        //     x.Name == this.PlcName.ToString() && x.Level == 3);
    }

    //protected IList<PlcPoint> ScanPlcAlarmInfoList(int? takeCount = null)
    //{
    //    return new List<PlcPoint>();
    //}

    private DateTime lastWarnDateTime = DateTime.Now;

    //public Dictionary<ushort, ushort> WarnDictionary = new Dictionary<ushort, ushort>();

    protected virtual void ModbusClientBaseOnScannedEvent(object sender, EventArgs e)
    {
        if (!this.Runing)
            return;

        DateTime now = DateTime.Now;
        if ((now - this.lastWarnDateTime).Seconds >= 5)
        {
            this.lastWarnDateTime = now;
            ScanPLCWarnList();
        }
    }

    public override IList<PlcPoint> ScanPlcWarnInfoList(int? takeCount = null)
    {
        IList<PlcPoint> warnPointList = new List<PlcPoint>();
        try
        {
            foreach (var plcPoint in this.WarnPointList)
            {
                //这里的错误报警信息都是1个字，2个字节，16位
                var pointInfo = this.ModbusClient.ReadScannedValue<ushort>(plcPoint.Address);
                if (pointInfo.Value != 0)
                {
                    //if (!this.WarnDictionary.ContainsKey(pointInfo.Address) || this.WarnDictionary[pointInfo.Address] != pointInfo.Value)
                    //{
                    //    this.Logger.LogError($"{this.stationName}异常点位[{pointInfo.Address}]值[{pointInfo.Value}]");
                    //    this.WarnDictionary[pointInfo.Address] = pointInfo.Value;
                    //}
                    //pointInfo.LastValue = pointInfo.Value.ToString();
                    warnPointList.Add(pointInfo);
                }
                // else
                // {
                //      //复位直接清空 不处理
                //     if(this.WranDictionary.ContainsKey(pointInfo.Address))
                //         this.WranDictionary.Remove(pointInfo.Address);
                // }
            }
        }
        catch (Exception ex)
        {
            this.Logger.LogError($"{this.stationName}异常信息[{ex.Message}]");
        }
        return warnPointList;
    }

    /// <summary>
    /// 扫描PLC报警信息，触发事件
    /// </summary>
    private void ScanPLCWarnList()
    {
        PLCErrorLists.Clear();
        foreach (var plcPoint in WarnPointList)
        {
            var pointInfo = this.ModbusClient.ReadScannedValue<ushort>(plcPoint.Address);
            bool isError = false;
            if (pointInfo.Value != 0)
            {
                for (int i = 0; i < 16; i++)
                {
                    if (((pointInfo.Value >> i) & 1) == 1)
                    {
                        var addr = plcPoint.Address.ToString() + "." + i.ToString();
                        var point = PLCErrorInfoList.FirstOrDefault(p => p.ErrorAddress.Equals(addr));
                        if (point != null)
                        {
                            isError = !point.ErrorInfo.Contains("提示");
                            PLCErrorLists.Add(point);
                        }
                    }
                }
                if (isError)
                {
                    //给BS那边只需要给报警信息
                    PLCErrorLists.Add(new PLCErrorPoint() { ErrorAddress = plcPoint.Address.ToString(), ErrorInfo = pointInfo.Value.ToString() }); //这边定义好传给BS的值
                }
            }
        }

        if (PLCErrorLists.Count > 0)
        {
            this.OnScanPlcErrorListEvent?.Invoke(this, PLCErrorLists);
        }
    }
    #endregion

    /// <summary>
    /// 用于移液枪取运行状态值
    /// </summary>
    /// <param name="resultString"></param>
    /// <returns></returns>
    protected string GetPipetteReturnCode(string resultString)
    {
        try
        {
            string pattern = @"er(\d{2})";
            MatchCollection matches = Regex.Matches(resultString, pattern);
            return matches[0].Groups[1].Value;
        }
        catch (Exception)
        {
            return resultString;
        }
    }
}