using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Common;
using Dao;
using Domain;
using RCUHost.Protocols;
using System.Threading.Tasks;
using System.Threading;
using CommonEntity;

namespace RCUHost.Implement
{
    public class HostSearchReceiver : GenericReceiverBase, IHostSearchReceiver
    {
        public static object objlock = new object();
        private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(HostSearchReceiver));

        public IHostRepository HostRepository { get; set; }
        public IHostModalRepository HostModalRepository { get; set; }
        public IRoomTypeModalRepository RoomTypeModalRepository { get; set; }
        public ISysHotelRepository SysHotelRepository { get; set; }
        public IGroupRepository GroupRepository { get; set; }
        public IRoomTypeRepository RoomTypeRepository { get; set; }
        public IDeviceSecretReceiver DeviceSecretReceiver { get; set; }
        public IHostRegisterReceiver HostRegisterReceiver { get; set; }//注册时通知同步主机信息

        private static bool searching = false;

        /// <summary>
        /// 当前搜索主机用户
        /// </summary>
        private static String user = "";

        private SearchHostResultHandler searchHostResultHandler;

        public void Start(SearchHostResultHandler handler)
        {
            searchHostResultHandler = handler;
            searching = true;
            HostServer.AddReceiver(this);
            Start();
        }

        public void Start()
        {
            //byte[] data = CreateSearchHostRequestPacket();
            //Send(data, MulticastIP, MulticastPort);
        }

        public bool Searching
        {
            get { return searching; }
        }

        public string User
        {
            get { return user; }
            set { user = value ?? String.Empty; }
        }

        public void Stop()
        {
            HostServer.RemoveReceiver(this);
            searchHostResultHandler = null;
            searching = false;
            user = "";
        }
        /// <summary>
        /// 修改协议：原来的搜索改成注册，当mac地址已存在时，更新数据，否则插入新主机
        /// </summary>
        /// <param name="context"></param>
        public override void Process(ReceiverContext context)
        {
            StepTongJi.SendInfo(4, "注册命令Task内部开始执行", context.MessageID, context.IsMonitor);
            //Reply(context);

            var OriginalByte = context.Data;

            int lll = OriginalByte.Length;
            var A1 = OriginalByte.Skip(15).Take(lll - 15 - 2).ToArray();

            int startIndex = StructConverter.SizeOf(context.SystemHeader);
            SearchHostPacketReply? reply = DecodeSearchHostPacketReply(context.Data, startIndex);
            SearchHostPacketReplyV2? C_Xilie_zhuji = null;
            if (context.Data.Length > 100)//V2版本新补充的内容
            {
                C_Xilie_zhuji = DecodeSearchHostPacketReplyV2(context.Data, 58);
            }
            if (reply.HasValue)
            {
                try
                {
                    string hhostnumber = context.SystemHeader.Value.HostNumber.ToString();
                    string hotelCode = context.SystemHeader.Value.HostNumber.ToHotelCode().ToString();//获取酒店编码
                    string mac = BitConverter.ToString(reply.Value.MAC);
                    string version = reply.Value.Version;
                    string ip = context.RemoteEndPoint.Address.ToString();
                    int port = context.RemoteEndPoint.Port;
                    Host exitEntity = null;
                    StringBuilder sbSQL = new StringBuilder();
                    sbSQL.Append("UPDATE tb_Hosts SET ");
                    if (C_Xilie_zhuji.HasValue)//C系列主机处理：只能靠后台手工添加
                    {
                        #region C系列主要
                        if (string.IsNullOrEmpty(context.SystemHeader.Value.HostNumber.ToString()))
                        {
                            //logger.Error(string.Format("C主机注册主机编号不能为空。HotelCode:{0},MAC:{1}", hotelCode, mac));
                            return;
                        }

                        Host EEE = null;
                        lock (objlock)
                        {
                            EEE = HostRepository.LoadByMac(mac).OrderByDescending(r => r.ID).FirstOrDefault();
                        }
                        if (EEE == null)
                        {
                            //logger.Error(string.Format("C主机注册通过MAC和版本号C开头找不到记录。HotelCode:{0},MAC:{1}", hotelCode, mac));
                            return;//通过mac地址找不到C系列主机，则不新增
                        }
                        if (string.IsNullOrEmpty(EEE.RoomNumber))
                        {
                            //logger.Error(string.Format("C主机注册通过MAC和版本号C开头找到记录的房号为空。HotelCode:{0},MAC:{1}", hotelCode, mac));
                            return;//如果房号是空，则不更新
                        }
                        string KKK1 = CacheKey.HostInfo_Key_MAC + "_" + hotelCode + "_" + mac;
                        string KKK2 = CacheKey.HostInfo_Key_HostNumber + "_" + hhostnumber;
                        object ooo = MemoryCacheHelper.Get(KKK1);
                        if (ooo != null)
                        {
                            exitEntity = (Host)ooo;
                        }
                        else
                        {
                            exitEntity = EEE;
                            MemoryCacheHelper.Set(KKK1, EEE);
                            MemoryCacheHelper.SlideSet(KKK2, EEE);
                        }
                        exitEntity.DNS = string.Join(".", C_Xilie_zhuji.Value.DNS);
                        sbSQL.Append("DNS='" + exitEntity.DNS + "'");
                        if (!version.ToUpper().StartsWith("C"))
                        {
                            version = "C" + version;//如果命令里的版本号不是C开头，则补上C
                        }
                        //if (exitEntity.RoomNumber != reply2.Value.RoomNumber)
                        //{
                        //    //如果房号不匹配，则给rcu发命令，同步房号
                        //}
                        #endregion
                    }
                    else
                    {
                        #region 老主机
                        string Key = CacheKey.HotelInfo_Key_Code + "_" + hotelCode; ;
                        object ooo = MemoryCacheHelper.Get(Key);
                        SysHotel sysHotel = null;
                        if (ooo != null)
                        {
                            sysHotel = (SysHotel)ooo;
                        }
                        else
                        {
                            sysHotel = SysHotelRepository.GetByCode(hotelCode);//获取酒店记录
                            MemoryCacheHelper.SlideSet(hotelCode, sysHotel);
                        }
                        if (sysHotel == null)//如果无酒店记录，则设置默认酒店
                        {
                            sysHotel = new SysHotel { ID = 1 };
                        }
                        exitEntity = HostRepository.GetByMAC(mac, sysHotel.ID);//根据mac地址获取指定酒店下主机
                        if (exitEntity == null)//老主机新增
                        {
                            var entity = new Host();
                            entity.HostNumber = context.SystemHeader.Value.HostNumber.ToString();
                            entity.RoomNumber = context.SystemHeader.Value.HostNumber.ToRoomNumber();
                            entity.MAC = mac;
                            entity.SysHotel = sysHotel;
                            Group group = GroupRepository.GetGroupList(sysHotel.ID).OrderBy(r => r.ID).FirstOrDefault();
                            entity.Group = group != null ? group : new Group { ID = 1 };
                            RoomType roomType = RoomTypeRepository.LoadAll().Where(r => r.HotelID == sysHotel.ID && r.Default == true).OrderBy(r => r.ID).FirstOrDefault();
                            entity.RoomType = roomType != null ? roomType : new RoomType { ID = 1 };
                            entity.IP = ip;
                            entity.Port = port;
                            entity.Version = reply.Value.Version;
                            entity.ConfigVersion = String.Join(".", reply.Value.ConfigVersion);
                            entity.SubnetMask = String.Join(".", reply.Value.SubnetMask);
                            entity.Gateway = String.Join(".", reply.Value.Gateway);
                            entity.Remark = hotelCode;
                            entity.RoomStatus = new RoomStatus { ID = 16 };//默认房态“空房”
                            entity.SafeStatus = 2;//默认未接保险箱
                            entity.RegisterDate = DateTime.Now;
                            entity.IsSyncRoomNumber = false;
                            entity.IsAutoUpdate = false;
                            entity.Last_Modified_Time = DateTime.Now;//标识有更新                                
                            entity = GetDeviceSecret(entity, ref sbSQL);//获取密钥
                            HostRepository.Save(entity);//保存主机
                            PublishDeviceSecret(entity);//下发密钥
                            Task.Factory.StartNew<bool>(() => UpdateHostModals(entity));//创建新回路
                            return;
                        }
                        else
                        {
                            sbSQL.Append("MAC='" + mac + "'");
                        }
                        #endregion
                    }

                    bool isChanged = false;
                    string hostNumber = context.SystemHeader.Value.HostNumber.ToString();
                    string configVersion = String.Join(".", reply.Value.ConfigVersion);
                    string subnetMask = String.Join(".", reply.Value.SubnetMask);
                    string gateway = String.Join(".", reply.Value.Gateway);
                    if (true)
                    //if (exitEntity.HostNumber != hostNumber)
                    {
                        exitEntity.HostNumber = hostNumber;
                        isChanged = true;
                        sbSQL.Append(",HostNumber='" + exitEntity.HostNumber + "'");
                    }
                    //if (exitEntity.Version != version)
                    if (true)
                    {
                        exitEntity.Version = version;
                        isChanged = true;
                        sbSQL.Append(",Version='" + exitEntity.Version + "'");
                    }
                    if (true)
                    //if (exitEntity.ConfigVersion != configVersion)
                    {
                        exitEntity.ConfigVersion = configVersion;
                        isChanged = true;

                        BarData bbb = new BarData();
                        bbb.HostID = exitEntity.ID;

                        string output = NormalizeVersion(exitEntity.ConfigVersion); // 输出 "15.0.0"
                        bbb.ConfiguraVersion = output;
                        UploadCurrentVersionReceiver.UP_Grade_Json(exitEntity, bbb);

                        sbSQL.Append(",ConfigVersion='" + exitEntity.ConfigVersion + "'");
                    }
                    //if (exitEntity.SubnetMask != subnetMask)
                    if (true)
                    {
                        exitEntity.SubnetMask = subnetMask;
                        isChanged = true;
                        sbSQL.Append(",SubnetMask='" + exitEntity.SubnetMask + "'");
                    }
                    //if (exitEntity.Gateway != gateway)
                    if (true)
                    {
                        exitEntity.Gateway = gateway;
                        isChanged = true;
                        sbSQL.Append(",Gateway='" + exitEntity.Gateway + "'");
                    }
                    //if (exitEntity.Remark != hotelCode)
                    if (true)
                    {
                        exitEntity.Remark = hotelCode;
                        isChanged = true;
                        sbSQL.Append(",Remark='" + exitEntity.Remark + "'");
                    }
                    if (isChanged)
                    {
                        exitEntity.Last_Modified_Time = DateTime.Now;//标识有更新
                        sbSQL.Append(",Last_Modified_Time=GETDATE()");
                    }
                    //if (exitEntity.IP != ip)
                    if (true)
                    {
                        exitEntity.IP = ip;
                        isChanged = true;
                        sbSQL.Append(",IP='" + exitEntity.IP + "'");
                    }
                    if (true)
                    //if (exitEntity.Port != port)
                    {
                        exitEntity.Port = port;
                        isChanged = true;
                        sbSQL.Append(",Port=" + exitEntity.Port);
                    }
                    //Host hostTemp = HostRepository.Get(exitEntity.ID);//重新获取主机最新升级更新状态数据
                    //exitEntity.UpgradeStatus = hostTemp.UpgradeStatus;
                    //exitEntity.UpgradeTime = hostTemp.UpgradeTime;
                    if (isChanged)
                    {
                        exitEntity = GetDeviceSecret(exitEntity, ref sbSQL);//获取密钥
                        sbSQL.Append(" WHERE ID=" + exitEntity.ID);

                        //string RegisterKey1 = "SearchHostPass";
                        //string RegisterKey2 = "SearchHostFilter";
                        //暂时的取消
                        if (hotelCode.Equals("1197"))
                        {
                            HostRepository.Update(sbSQL.ToString());//更新主机，用sql语句更新更高效
                        }
                        else
                        {

                            //string KKK = "RegisterKey_" + hhostnumber;
                            //object OOO = MemoryCacheHelper.Get(KKK);
                            //if (OOO != null)
                            //{
                            //    RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey2, hotelCode);
                            //}
                            //else
                            //{
                            //    string ti = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                            //    MemoryCacheHelper.Set(KKK, ti, DateTimeOffset.Now.AddMinutes(5));
                            //    HostRepository.Update(sbSQL.ToString());//更新主机，用sql语句更新更高效
                            //    RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey1, hotelCode);
                            //}
                            HostRepository.Update(sbSQL.ToString());//更新主机，用sql语句更新更高效

                            //有升级的时候，不能被跳过
                            string Key = "Upgrade_UpdateSQL_" + exitEntity.HostNumber;
                            object OOO1 = MemoryCacheHelper.Get(Key);
                            if (OOO1 != null)
                            {
                                HostRepository.Update(sbSQL.ToString());//更新主机，用sql语句更新更高效
                                MemoryCacheHelper.Delete(Key);
                            }
                        }

                        PublishDeviceSecret(exitEntity);//下发密钥
                    }
                    if (exitEntity.Version.StartsWith("C"))
                    {
                        CSRedisCacheHelper.Set(mac, exitEntity.IP + ":" + exitEntity.Port);//心跳包更新

                        string RegisterKey1 = "HostSearchReceiveDrop";
                        RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey1, hotelCode);

                        //这里的功能暂时去掉
                        //这里会发送 B1 数据 一定 要注意
                        //B1不能被去掉
                        HostRegisterReceiver.Send(exitEntity);//通知同步工具

                        //logger.Error(string.Format("通知酒店({0})客房({1})同步主机信息。", exitEntity.SysHotel.Code, exitEntity.RoomNumber));
                    }

                    string HKey1 = CacheKey.HostInfo_Key_MAC + hotelCode + "_" + mac;
                    string HKey = CacheKey.HostInfo_Key_HostNumber + "_" + hostNumber;
                    object takeout_obj = MemoryCacheHelper.Get(HKey);
                    if (takeout_obj == null)
                    {
                        MemoryCacheHelper.SlideSet(HKey, exitEntity);
                        MemoryCacheHelper.SlideSet(HKey1, exitEntity);
                    }


                    string YiJingChuLiGuo = CacheKey.AllReadyDealWith01_Prefix + "_" + hostNumber;
                    MemoryCacheHelper.Set(YiJingChuLiGuo, A1, DateTimeOffset.Now.AddMinutes(5));
                    StepTongJi.SendInfo(5, "注册命令Task内部执行完毕", context.MessageID, context.IsMonitor);
                }
                catch (Exception ex)
                {
                    logger.Error(string.Format("终端注册失败，来自：{0}，原因：{1}，数据：{2}", context.RemoteEndPoint.Address.ToString(), ex.ToString(), Tools.ByteToString(context.Data)));
                }
            }
        }

        public static string NormalizeVersion(string version, int desiredParts = 3)
        {
            // 移除末尾的冗余点并分割
            var parts = version.TrimEnd('.').Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);

            // 补零到目标位数
            while (parts.Length < desiredParts)
            {
                parts = parts.Concat(new[] { "0" }).ToArray();
            }

            return string.Join(".", parts);
        }

        /// <summary>
        /// 获取主机设备密钥
        /// </summary>
        /// <param name="host"></param>
        /// <returns></returns>
        private Host GetDeviceSecret(Host host, ref StringBuilder sbSQL)
        {
            //如果所属酒店需要自动获取密钥，且目前密钥是空，则自动获取
            if (host.SysHotel.IsAutoGetKey && string.IsNullOrEmpty(host.DeviceSecret))
            {
                DeviceRegisterResult resultData = FreeGoOperation.DeviceRegister(host.MAC);
                if (resultData.errcode == "0")
                {
                    host.DeviceName = resultData.device_name;
                    sbSQL.Append(",DeviceName='" + host.DeviceName + "'");
                    host.DeviceSecret = resultData.device_secret;
                    sbSQL.Append(",DeviceSecret='" + host.DeviceSecret + "'");
                    host.IotId = resultData.iot_id;
                    sbSQL.Append(",IotId='" + host.IotId + "'");
                    host.ProductKey = resultData.product_key;
                    sbSQL.Append(",ProductKey='" + host.ProductKey + "'");
                    host.IsPublish = false;
                    sbSQL.Append(",IsPublish=0");
                }
                else
                {
                    logger.Error(string.Format("调用FreeGo接口返回错误：RoomNumber:{0},ErrorCode:{1},ErrorMessage:{2}", host.RoomNumber, resultData.errcode, resultData.msg));
                }
            }
            return host;
        }
        /// <summary>
        /// 下发设备密钥
        /// </summary>
        /// <param name="host"></param>
        private void PublishDeviceSecret(Host host)
        {
            if (!host.IsPublish && !string.IsNullOrEmpty(host.DeviceSecret))
            {
                DeviceSecretReceiver.Send(host);
                HostRepository.SetPublish(host, true);
            }
        }
        /// <summary>
        /// 创建新回路
        /// </summary>
        /// <param name="host"></param>
        /// <returns></returns>
        private bool UpdateHostModals(Host host)
        {
            if (host == null)
            {
                return false;
            }
            HostModalRepository.DeteleByHostID(host.ID);
            var list = RoomTypeModalRepository.LoadAll().Where(r => r.RoomType == host.RoomType);
            DateTime now = DateTime.Now;
            foreach (var modal in list)
            {
                HostModalRepository.Save(new HostModal { HostID = host.ID, Modal = modal, Status = 2, Time = 0, UpdateTime = now });
            }
            return true;
        }

        public override CommandType CommandType
        {
            get { return CommandType.SearchHost; }
        }

        #region Private Methods

        private byte[] CreateSearchHostRequestPacket()
        {
            SystemHeader systemHeader = CreateSystemHeader();

            SearchHostPacket searchHostPacket = CreateSearchHostPacket();

            int size = StructConverter.SizeOf(systemHeader) + StructConverter.SizeOf(searchHostPacket);

            systemHeader.FrameLength = (ushort)size;

            byte[] buffer = new byte[size];

            byte[] src1 = StructConverter.StructToBytes(systemHeader);
            Array.Copy(src1, 0, buffer, 0, src1.Length);

            byte[] src3 = StructConverter.StructToBytes(searchHostPacket);
            Array.Copy(src3, 0, buffer, src1.Length, src3.Length);

            return buffer;
        }

        private SearchHostPacket CreateSearchHostPacket()
        {
#if DEBUG
            var ip = Tools.GetLocalIP();
#else
			var ip = MessageIP;
#endif

            SearchHostPacket packet = new SearchHostPacket
            {
                IsSave = 1,
                IP = IPAddress.Parse(ip).GetAddressBytes(),
                Port = Convert.ToUInt16(MessagePort)
            };

            return packet;
        }

        /// <summary>
        /// 解码 SearchHostPacketReply
        /// </summary>
        /// <param name="data"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        private SearchHostPacketReply? DecodeSearchHostPacketReply(byte[] data, int startIndex)
        {
            return StructConverter.BytesToStruct(data, startIndex, typeof(SearchHostPacketReply)) as SearchHostPacketReply?;
        }

        private SearchHostPacketReplyV2? DecodeSearchHostPacketReplyV2(byte[] data, int startIndex)
        {
            return StructConverter.BytesToStruct(data, startIndex, typeof(SearchHostPacketReplyV2)) as SearchHostPacketReplyV2?;
        }

        #endregion
    }
}
