using PlcSiemens.Core.Extension;
using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.Redis;
using WCS.Core;
using WCS.Entity.Protocol.BCR;
using WCS.Entity.Protocol.Robot;
using WCS.Entity.Protocol.Station;
using WCS.Entity.Protocol.Truss;

namespace WCS.WorkEngineering.Extensions
{
    /// <summary>
    ///  设备扩展
    /// </summary>
    public static class DeviceExtension
    {
        #region 设备类型

        public static List<ProtocolInfo> ProtocolInfos = new List<ProtocolInfo>();

        /// <summary>
        ///  是否是巷道
        /// </summary>
        /// <param name="source">设备信息</param>
        /// <returns></returns>
        public static bool IsTunnel(this Device source)
        {
            return source.HasFlag(DeviceFlags.巷道);
        }

        #endregion 设备类型

        #region 标签判断

        public static bool HasFlag(this Device device, params DeviceFlags[] flag)
        {
            return flag.Any(device.HasFlag);
        }

        #endregion 标签判断

        #region 协议操作扩展

        public static void AddProtocol<T>(this Device device, int position, ushort db, string ip)
        {
            var info = new ProtocolInfo
            {
                Position = position,
                DBInfo = new DBInfo
                {
                    No = db,
                    PLCInfo = new PLCInfo
                    {
                        IP = ip,
                        Port = 102,
                        Rack = 0,
                        Slot = 1,
                        Type = PLCType.Siemens
                    }
                }
            };
            ProtocolInfos.Add(info);
            device.AddProtocol<T>(info);
        }

        #endregion 协议操作扩展

        #region 设备扩展方法

        /// <summary>
        ///  入库站点是否被禁止
        /// </summary>
        /// <returns></returns>
        public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523> device)
        {
            var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
            var configs = config.Split(",");
            if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用，请联系运维人员了解具体情况", LogLevelEnum.High);
        }

        /// <summary>
        ///  入库站点是否被禁止
        /// </summary>
        /// <returns></returns>
        public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IBCR81> device)
        {
            var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
            var configs = config.Split(",");
            if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用，请联系运维人员了解具体情况", LogLevelEnum.High);
        }

        /// <summary>
        ///  入库站点是否被禁止
        /// </summary>
        /// <returns></returns>
        public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IStation91> device)
        {
            var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
            var configs = config.Split(",");
            if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用，请联系运维人员了解具体情况", LogLevelEnum.High);
        }

        /// <summary>
        ///  入库站点是否被禁止
        /// </summary>
        /// <returns></returns>
        public static void 入库站点是否被禁止(this Device<IStation520, IStation521, IStation523, IStation91, IBCR81> device)
        {
            var config = RedisHub.Default.Check("ForbidTubuEnter") ?? throw new Exception("请在Redis中配置入库口禁用");
            var configs = config.Split(",");
            if (configs.Contains(device.Entity.Code)) throw new KnownException("当前入库口已被禁用，请联系运维人员了解具体情况", LogLevelEnum.High);
        }

        /// <summary>
        ///  入库站点是否满足执行条件
        /// </summary>
        /// <returns></returns>
        public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523> device)
        {
        }

        ///// <summary>
        /////  入库站点是否满足执行条件
        ///// </summary>
        ///// <returns></returns>
        //public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IBCR81> device)
        //{
        //    if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
        //    if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
        //    if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
        //    if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
        //}

        ///// <summary>
        /////  入库站点是否满足执行条件
        ///// </summary>
        ///// <returns></returns>
        //public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IStation91> device)
        //{
        //    if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
        //    if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
        //    if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
        //    if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
        //}

        ///// <summary>
        /////  入库站点是否满足执行条件
        ///// </summary>
        ///// <returns></returns>
        //public static void 入库站点是否满足执行条件(this Device<IStation520, IStation521, IStation523, IStation91, IBCR81> device)
        //{
        //    if (device.Data.VoucherNo != device.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{device.Data.VoucherNo}-DB521:{device.Data2.VoucherNo}", LogLevelEnum.High);
        //    if (device.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
        //    if (device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 0) throw new KnownException("有光电无请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status) && device.Data2.Request == 1) throw new KnownException("无光电有请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
        //    if (device.Data2.Request != 1.ToShort()) throw new KnownException("无请求", LogLevelEnum.Mid);
        //    if (!device.Data3.Status.HasFlag(StationStatus.PH_Status)) throw new KnownException("无光电", LogLevelEnum.Mid);
        //    if (device.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
        //}

        /// <summary>
        ///  获取BCR码
        /// </summary>
        /// <returns></returns>
        public static string GetBCRCode(this IBCR81 bCR)
        {
            var barcode = bCR.Content.RemoveEscapeCharacters();
            return barcode;
        }

        ///// <summary>
        /////  获取历史扫码记录
        ///// </summary>
        ///// <returns></returns>
        //public static List<string> GetBcrCodeList(this IBCR83 bCR)
        //{
        //    return new List<string>() {
        //        bCR.BcrCode1.RemoveEscapeCharacters(),
        //        bCR.BcrCode2.RemoveEscapeCharacters(),
        //        bCR.BcrCode3.RemoveEscapeCharacters(),
        //        bCR.BcrCode4.RemoveEscapeCharacters(),
        //        bCR.BcrCode5.RemoveEscapeCharacters(),
        //        bCR.BcrCode6.RemoveEscapeCharacters(),
        //        bCR.BcrCode7.RemoveEscapeCharacters(),
        //        bCR.BcrCode8.RemoveEscapeCharacters(),
        //        bCR.BcrCode9.RemoveEscapeCharacters(),
        //        bCR.BcrCode10.RemoveEscapeCharacters(),
        //        bCR.BcrCode11.RemoveEscapeCharacters() };
        //}

        /// <summary>
        ///  获取缓存列表
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<string> GetBcrCodeList(this IStation525 station525)
        {
            var properties = station525.GetType().GetProperties().ToArray();
            var index = 1;
            for (var i = 1; i <= 50; i++)
            {
                var value = properties[index].GetValue(station525).ToString().RemoveEscapeCharacters();
                if (!value.IsNullOrEmpty()) yield return value;
                index += 7;
            }
        }

        /// <summary>
        ///  获取缓存列表
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<int> GetTaskNoList(this ITruss531 station525)
        {
            var properties = station525.GetType().GetProperties().ToArray();
            var index = 0;
            for (var i = 0; i <= 59; i++)
            {
                var value = properties[index].GetValue(station525)!.ToInt();
                if (value > 0) yield return value;
                index += 1;
            }
        }

        /// <summary>
        ///  获取缓存列表
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<int> GetTaskNoList(this IRobot531 station525)
        {
            var properties = station525.GetType().GetProperties().ToArray();
            var index = 0;
            for (var i = 0; i <= 29; i++)
            {
                var value = properties[index].GetValue(station525)!.ToInt();
                if (value > 0) yield return value;
                index += 1;
            }
        }

        /// <summary>
        ///  通过仓库编码获取对应堆垛机信息
        /// </summary>
        /// <param name="warehouseCode">仓库编码</param>
        /// <returns></returns>
        public static string WarehouseToSrm(this string warehouseCode)
        {
            return warehouseCode switch
            {
                "1N" => "SRM1",
                "1S" => "SRM2",
                "2N" => "SRM3",
                "2S" => "SRM4",
                "3N" => "SRM5",
                "3S" => "SRM6",
                _ => "Error"
            };
        }

        #endregion 设备扩展方法

        /// <summary>
        ///  获取仓库号
        /// </summary>
        public static string GetWareCode(this string add)
        {
            return add switch
            {
                #region 库一

                //北
                "SRM1" => "1N",
                "2532" => "1N",
                "2527" => "1N",
                "2528" => "1N",
                "418" => "1N",
                "1606" => "1N",
                "1666" => "1NR",
                "1661" => "1NR",
                "18" => "1N",
                //南
                "SRM2" => "1S",
                "2732" => "1S",
                "2727" => "1S",
                "2728" => "1S",
                "618" => "1S",
                "1676" => "1SR",
                "1681" => "1SR",

                #endregion 库一

                #region 库二

                //北
                "SRM3" => "2N",
                "818" => "2N",
                "1691" => "2NR",
                "1696" => "2NR",
                //南
                "SRM4" => "2S",
                "1018" => "2S",
                "3128" => "2S",
                "1711" => "2SR",
                "1706" => "2SR",

                #endregion 库二

                #region 库二

                //北
                "SRM5" => "3N",
                "1218" => "3N",
                "1721" => "3NR",
                "1726" => "3NR",
                //南
                "SRM6" => "3S",
                "1418" => "3S",
                "1736" => "3SR",
                "1741" => "3SR",

                #endregion 库二

                _ => "",
            };
        }
    }

    /// <summary>
    ///  设备标签
    /// </summary>
    [Flags]
    public enum DeviceFlags : ulong

    {
        扫码 = 1L << 0,
        称重 = 1L << 1,
        外检 = 1L << 2,

        顶升 = 1L << 3,
        移栽 = 1L << 4,
        旋转 = 1L << 5,

        入库 = 1L << 6,
        出库 = 1L << 7,

        巷道口 = 1L << 8,
        RGV口 = 1L << 9,
        AGV取货站台口 = 1L << 10,

        直轨 = 1L << 11,
        弯轨 = 1L << 12,
        环轨 = 1L << 13,

        巷道 = 1L << 14,
        堆垛机 = 1L << 15,
        输送机 = 1L << 16,

        #region 一轨双车堆垛机

        一列堆垛机 = 1L << 23,
        二列堆垛机 = 1L << 24,

        #endregion 一轨双车堆垛机

        RGV = 1L << 25,
        桁架 = 1L << 26,
        一楼扫码 = 1L << 27,
        满轮主线第一次扫码 = 1L << 28,
        主线分流点 = 1L << 29,
        一楼叠盘机 = 1L << 30,
        环形库分流点 = 1L << 31,
        桁架分流点 = 1L << 32,
        桁架缓存放行点 = 1L << 33,
        桁架取货点 = 1L << 34,
        拆盘机 = 1L << 35,
        桁架码垛位 = 1L << 36,
        环形库码垛工位 = 1L << 37,
        Robot = 1L << 38,
        桁架09缓存放行点 = 1L << 39,
        桁架18缓存放行点 = 1L << 40,
        桁架09异常缓存放行点 = 1L << 41,
        二次码垛RGV取货口 = 1L << 42,
        无交互触发设备 = 1L << 43,
    }

    /// <summary>
    /// 输送机段信息
    /// </summary>
    public class StationSegmentInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="start">起始设备号</param>
        /// <param name="end">结束设备号</param>
        /// <param name="ip">ip</param>
        public StationSegmentInfo(int start, int end, string ip)
        {
            Start = start;
            End = end;
            Ip = ip;
        }

        /// <summary>
        /// 起始设备编号
        /// </summary>
        public int Start { get; set; }

        /// <summary>
        ///结束设备编号
        /// </summary>
        public int End { get; set; }

        /// <summary>
        ///  输送机段所属IP
        /// </summary>
        public string Ip { get; set; }
    }

    /// <summary>
    /// RGV信息
    /// </summary>
    public class RgvSegmentInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="code"></param>
        /// <param name="ip">ip</param>
        public RgvSegmentInfo(int code, string ip)
        {
            Code = code;
            Ip = ip;
        }

        /// <summary>
        /// 设备编号
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        ///  输送机段所属IP
        /// </summary>
        public string Ip { get; set; }
    }

    /// <summary>
    /// 桁架信息
    /// </summary>
    public class TrussSegmentInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="code"></param>
        /// <param name="ip">ip</param>
        public TrussSegmentInfo(int code, string ip)
        {
            Code = code;
            Ip = ip;
        }

        /// <summary>
        /// 设备编号
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        ///  输送机段所属IP
        /// </summary>
        public string Ip { get; set; }
    }

    /// <summary>
    ///  扫码器信息
    /// </summary>
    public class BcrInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="ip">ip</param>
        public BcrInfo(string[] deviceNo, string ip)
        {
            DeviceNo = deviceNo;
            Ip = ip;
        }

        /// <summary>
        ///  设备编号
        /// </summary>
        public string[] DeviceNo { get; set; }

        /// <summary>
        ///  ip
        /// </summary>
        public string Ip { get; set; }
    }

    /// <summary>
    ///  外形信息
    /// </summary>
    public class ShapeInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="ip">ip</param>
        public ShapeInfo(int[] deviceNo, string ip)
        {
            DeviceNo = deviceNo;
            Ip = ip;
        }

        /// <summary>
        ///  设备编号
        /// </summary>
        public int[] DeviceNo { get; set; }

        /// <summary>
        ///  ip
        /// </summary>
        public string Ip { get; set; }
    }

    /// <summary>
    /// 路径信息
    /// </summary>
    public class RouteInfo
    {
        /// <summary>
        ///  构造函数
        /// </summary>
        /// <param name="deviceCode">起始点设备号</param>
        /// <param name="nextList">下一个设备集合</param>
        public RouteInfo(string deviceCode, string[] nextList)
        {
            DeviceCode = deviceCode;
            NextList = nextList;
        }

        /// <summary>
        ///  设备号
        /// </summary>
        public string DeviceCode { get; set; }

        /// <summary>
        ///  下一个设备
        /// </summary>
        public string[] NextList { get; set; }
    }

    /// <summary>
    ///  缓存分流信息
    /// </summary>
    public class CacheBcr
    {
        public CacheBcr(string bcrCode, short nextAdd)
        {
            BcrCode = bcrCode;
            NextAdd = nextAdd;
        }

        /// <summary>
        ///  条码
        /// </summary>
        public string BcrCode { get; set; }

        /// <summary>
        ///  下一个地址
        /// </summary>
        public short NextAdd { get; set; }
    }
}
