using System;
using System.Collections.Generic;
using Dapper;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Text;
using System.Net;
using Repository.Models;
using Microsoft.Extensions.Options;
using System.IO;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Repository.Services.Implement
{
    public class ObixApiConfig
    {
        public string ApiBase { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
    }

    public class Variable
    {
        public string System_type { get; set; }
        public string System_key { get; set; }
        public string system_value { get; set; }
    }

    public class DeviceSubscrip
    {
        public string building_guid { get; set; }
        public string main_system_guid { get; set; }
        public string sub_system_guid { get; set; }
        public string device_number { get; set; }
    }

    public class OntimeDeviceSubscripService
    {
        private readonly IDbConnection conn;
        private readonly IDbTransaction trans;
        private readonly IOptions<ObixApiConfig> _obixApiConfig;

        public OntimeDeviceSubscripService(IDbConnection conn, IDbTransaction trans, IOptions<ObixApiConfig> _obixApiConfig)
        {
            this.conn = conn;
            this.trans = trans;
            this._obixApiConfig = _obixApiConfig;
        }

        private string InsertGenerateString(List<string> properties, string table_name)
        {
            var insertQuery = new StringBuilder($"INSERT INTO {table_name} ");

            insertQuery.Append("(");

            properties.ForEach(prop => { insertQuery.Append($"{table_name}.{prop.Replace("@", "")},"); });

            insertQuery
                .Remove(insertQuery.Length - 1, 1)
                .Append(") VALUES (");

            properties.ForEach(prop => { insertQuery.Append($"{prop},"); });

            insertQuery
                .Remove(insertQuery.Length - 1, 1)
                .Append(");");

            return insertQuery.ToString();
        }

        public void MaintainOntimeDeviceSubscription(string targetTable, string mode, Dictionary<string, object> targetData, string origData = null)
        {
            List<Dictionary<string, object>> final_device_subscrip = new List<Dictionary<string, object>>();
            List<DeviceSubscrip> tempDeviceSubscrips = new List<DeviceSubscrip>();
            //判斷來源是什麼資料表
            if ("device" == targetTable)
            {   //設備表格
                switch (mode)
                {
                    case "delete": //軟刪除
                        //直接刪除該設備
                        object device_guid = null;
                        var has_device_guid = targetData.TryGetValue("device_guid", out device_guid);

                        var sql_device = $@"SELECT device_number FROM device WHERE device_guid = @device_guid";
                        var device_number = conn.QueryFirstOrDefault<string>(sql_device, new { device_guid = device_guid.ToString() }, trans);

                        if (!string.IsNullOrEmpty(device_number))
                        {
                            var purge_for_delete_sql = $@"DELETE FROM ontime_device_subscription WHERE device_number = @device_number";
                            conn.Execute(purge_for_delete_sql, new { device_number = device_number }, trans);
                        }
                        break;
                }
            }
            else if ("device_item" == targetTable)
            {   //點位表格
                List<DeviceSubscrip> deviceSubscrips = new List<DeviceSubscrip>();
                // step 1 找出所有該系統小類的設備
                if (mode != "delete")
                {
                    var sql_device = $@"SELECT building_guid, main_system_guid, sub_system_guid, device_number FROM device WHERE deleted = 0 AND sub_system_guid = @sub_system_guid";
                    object sub_system_guid = null;
                    var has_value = targetData.TryGetValue("@sub_system_guid", out sub_system_guid);

                    deviceSubscrips = conn.Query<DeviceSubscrip>(sql_device, new { sub_system_guid = sub_system_guid.ToString() }).ToList();
                    tempDeviceSubscrips = deviceSubscrips;
                }
                else
                {   //需先找出該點位的sub_system_guid
                    object device_item_guid = null;
                    var has_value = targetData.TryGetValue("device_item_guid", out device_item_guid);

                    if (has_value)
                    {
                        var sql_device_item = $@"SELECT sub_system_guid FROM device_item WHERE device_item_guid = @device_item_guid";
                        var sub_system_guid = conn.QueryFirstOrDefault<string>(sql_device_item, new { device_item_guid = device_item_guid.ToString() });

                        var sql_device = $@"SELECT building_guid, main_system_guid, sub_system_guid, device_number FROM device WHERE deleted = 0 AND sub_system_guid = @sub_system_guid";
                        deviceSubscrips = conn.Query<DeviceSubscrip>(sql_device, new { sub_system_guid = sub_system_guid.ToString() }).ToList();
                        tempDeviceSubscrips = deviceSubscrips;
                    }
                }

                //判斷是什麼模式,ex:insert、insert_list、update...等
                switch (mode)
                {
                    case "insert": //新增
                        List<Dictionary<string, object>> insertDics = new List<Dictionary<string, object>>();

                        object point_name = null;
                        var has_point_value = targetData.TryGetValue("@points", out point_name);
                        if (has_point_value)
                        {
                            foreach (var deviceSubscrip in deviceSubscrips)
                            {
                                Dictionary<string, object> insertDic = new Dictionary<string, object>()
                                {
                                    { "@building_guid", deviceSubscrip.building_guid },
                                    { "@main_system_guid", deviceSubscrip.main_system_guid },
                                    { "@sub_system_guid", deviceSubscrip.sub_system_guid },
                                    { "@device_number", deviceSubscrip.device_number },
                                    { "@name", point_name}
                                };

                                insertDics.Add(insertDic);
                            }
                        }

                        List<string> properties = insertDics.First().Keys.ToList();
                        string sql = InsertGenerateString(properties, "ontime_device_subscription");
                        conn.Execute(sql, insertDics, trans);
                        final_device_subscrip = insertDics;

                        break;
                    case "update": //更新

                        if (origData != null)
                        {
                            var device_point_name = origData;
                            //刪除訂閱表的資料
                            var purge_sql = $@"DELETE FROM ontime_device_subscription WHERE name=@name AND device_number IN @device_number";
                            conn.Execute(purge_sql, new { name = device_point_name, device_number = deviceSubscrips.Select(x => x.device_number).ToList() }, trans);
                        }

                        //新增訂閱表的資料
                        List<Dictionary<string, object>> insertDics2 = new List<Dictionary<string, object>>();

                        object point_name2 = null;
                        var has_point_value2 = targetData.TryGetValue("@points", out point_name);
                        if (has_point_value2)
                        {
                            foreach (var deviceSubscrip in deviceSubscrips)
                            {
                                Dictionary<string, object> insertDic = new Dictionary<string, object>()
                                {
                                    { "@building_guid", deviceSubscrip.building_guid },
                                    { "@main_system_guid", deviceSubscrip.main_system_guid },
                                    { "@sub_system_guid", deviceSubscrip.sub_system_guid },
                                    { "@device_number", deviceSubscrip.device_number },
                                    { "@name", point_name}
                                };

                                insertDics2.Add(insertDic);
                            }
                        }

                        List<string> properties2 = insertDics2.First().Keys.ToList();
                        string sql2 = InsertGenerateString(properties2, "ontime_device_subscription");
                        conn.Execute(sql2, insertDics2, trans);
                        final_device_subscrip = insertDics2;
                        break;

                    case "delete": //軟刪除
                        //找出原本的
                        object delete_device_item_guid = null;
                        var has_delete_device_item_guid = targetData.TryGetValue("device_item_guid", out delete_device_item_guid);

                        if (has_delete_device_item_guid)
                        {
                            var sql_device_item = $@"SELECT points FROM device_item WHERE device_item_guid = @device_item_guid";
                            var delete_device_point_name = conn.QueryFirst<string>(sql_device_item, new { device_item_guid = delete_device_item_guid.ToString() });

                            //刪除訂閱表的資料
                            var purge_for_delete_sql = $@"DELETE FROM ontime_device_subscription WHERE name=@name AND device_number IN @device_number";
                            conn.Execute(purge_for_delete_sql, new { name = delete_device_point_name, device_number = deviceSubscrips.Select(x => x.device_number).ToList() }, trans);
                        }
                        break;
                }
            }

            #region step 2 設定要訂閱的設備點位
            var subscripUriFormat = @" <uri val='/obix/config/Arena/{0}/{1}/{2}/out/' />";

            List<string> subscripStrings = new List<string>();

            foreach (var deviceSubscrip in final_device_subscrip)
            {
                List<string> devicePaths = new List<string>();

                object device_number = null;
                var has_device_number = deviceSubscrip.TryGetValue("@device_number", out device_number);

                //拆解設備編號來組出路徑
                var deviceSubscripSplit = device_number.ToString().Split("_");
                foreach (var temp in deviceSubscripSplit)
                {
                    if (temp[0].ToString().All(char.IsDigit))
                    {
                        devicePaths.Add($"$3{temp}");
                    }
                    else
                    {
                        devicePaths.Add(temp);
                    }
                }

                //剔除最後一個,因為是設備名稱
                devicePaths.RemoveAt(devicePaths.Count() - 1);

                object point_name = null;
                var has_point_name = deviceSubscrip.TryGetValue("@name", out point_name);

                subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), device_number.ToString(), point_name.ToString()));
            }

            #endregion step 2 設定要訂閱的設備點位

            #region step 3 訂閱設備點位,並將回傳的值新增至資料庫
            EDFunction ed = new EDFunction();

            string userName = ed.AESDecrypt(_obixApiConfig.Value.UserName);
            string password = ed.AESDecrypt(_obixApiConfig.Value.Password);

            String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(userName + ":" + password));

            var sql_watch = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = @system_type AND system_key = @system_key";

            var watch = conn.QueryFirstOrDefault<Variable>(sql_watch, new { system_type = "obixConfig", system_key = "watch_id" });

            HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{_obixApiConfig.Value.ApiBase}obix/watchService/watch{watch.system_value}/add/");
            addWatchServiceRequest.Method = "POST";
            addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
            addWatchServiceRequest.PreAuthenticate = true;

            var subscripFullString = $@"<obj is='obix: WatchIn'>
                                                <list names = 'hrefs'>
                                                    {string.Join(null, subscripStrings)}
                                                </list>
                                            </obj>";
            byte[] byteArray = Encoding.UTF8.GetBytes(subscripFullString);
            using (Stream reqStream = addWatchServiceRequest.GetRequestStream())
            {
                reqStream.Write(byteArray, 0, byteArray.Length);
            }

            HttpWebResponse addWatchServiceResponse = (HttpWebResponse)addWatchServiceRequest.GetResponse();
            var addWatchServiceResponseContent = new StreamReader(addWatchServiceResponse.GetResponseStream()).ReadToEnd();

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(addWatchServiceResponseContent);
            string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
            JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson);

            if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤
            {
                throw new NotImplementedException("設備點位訂閱失敗");

                //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】");
                //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】[錯誤內容]:{0}", addWatchServiceJsonResult);
            }

            if (addWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容
            {
                List<Dictionary<string, object>> ontimeRawDatas = new List<Dictionary<string, object>>();

                var ontimeList = addWatchServiceJsonResult["obj"]["list"];
                if (ontimeList["real"] != null && ontimeList["real"].HasValues)
                {
                    //讀取數值型
                    foreach (var real in ontimeList["real"])
                    {
                        var valueSplit = real["@display"].ToString().Split();
                        var value = valueSplit[0];
                        var href = real["@href"].ToString();
                        var hrefSplit = href.Split("/");
                        var findOutIndex = 0;
                        var outIndex = 0;
                        foreach (var tempHref in hrefSplit) //找出out的Index
                        {
                            if (tempHref == "out")
                            {
                                outIndex = findOutIndex;
                            }
                            findOutIndex++;
                        }

                        var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號
                        var name = hrefSplit[outIndex - 1];//透過outIndex找出點位

                        var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();

                        Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
                            {
                                { "@building_guid", selectDevice.building_guid },
                                { "@main_system_guid", selectDevice.main_system_guid },
                                { "@sub_system_guid", selectDevice.sub_system_guid },
                                { "@device_number", device_number},
                                { "@name", name},
                                { "@value", value},
                                { "@is_bool", 0},
                            };

                        ontimeRawDatas.Add(ontimeRawData);
                    }
                }

                if (ontimeList["bool"] != null && ontimeList["bool"].HasValues)
                {
                    //讀取布林型
                    foreach (var real in ontimeList["bool"])
                    {
                        var valueSplit = real["@display"].ToString().Split();
                        var value = valueSplit[0];
                        var href = real["@href"].ToString();
                        var hrefSplit = href.Split("/");
                        var findOutIndex = 0;
                        var outIndex = 0;
                        foreach (var tempHref in hrefSplit) //找出out的Index
                        {
                            if (tempHref == "out")
                            {
                                outIndex = findOutIndex;
                            }
                            findOutIndex++;
                        }

                        var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號
                        var name = hrefSplit[outIndex - 1];//透過outIndex找出點位

                        var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();

                        Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
                            {
                                { "@building_guid", selectDevice.building_guid },
                                { "@main_system_guid", selectDevice.main_system_guid },
                                { "@sub_system_guid", selectDevice.sub_system_guid },
                                { "@device_number", device_number},
                                { "@name", name},
                                { "@value", value},
                                { "@is_bool", 1},
                            };

                        ontimeRawDatas.Add(ontimeRawData);
                    }
                }

                if (ontimeRawDatas.Count() > 0)
                {
                    try
                    {
                        var insert_update_sql = $@"INSERT INTO ontime_device_rawdata (building_guid, main_system_guid, sub_system_guid, device_number, name, value, is_bool) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @value, @is_bool)
                                                    ON DUPLICATE KEY UPDATE value=@value, is_bool = @is_bool";
                        conn.Execute(insert_update_sql, ontimeRawDatas);
                    }
                    catch (Exception exception)
                    {
                        throw new NotImplementedException("新增設備點位原始資料失敗", exception);

                        //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】");
                        //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]:{0}", exception.ToString());
                    }
                }

                //logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務完成】");
            }

            #endregion step 3 訂閱設備點位,並將回傳的值新增至資料庫

        }

        /// <summary>
        /// 維護多筆的設備點位訂閱表
        /// </summary>
        /// <param name="targetTable"></param>
        /// <param name="mode"></param>
        /// <param name="targetDataList"></param>
        public void MaintainMutiOntimeDeviceSubscription(string targetTable, List<Dictionary<string, object>> targetDataList)
        {
            //只有新增設備時,會有多筆
            if (targetTable == "device")
            {
                List<string> points = new List<string>();
                // step 1 找出所有該系統小類的點位
                var sql_points = $@"SELECT points FROM device_item WHERE deleted = 0 AND sub_system_guid = @sub_system_guid";
                object sub_system_guid = null;
                var has_value = targetDataList.First().TryGetValue("@sub_system_guid", out sub_system_guid);

                points = conn.Query<string>(sql_points, new { sub_system_guid = sub_system_guid.ToString() }).ToList();

                List<Dictionary<string, object>> insertDics = new List<Dictionary<string, object>>();
                List<DeviceSubscrip> tempDeviceSubscrips = new List<DeviceSubscrip>();
                foreach (var targetData in targetDataList)
                {
                    object device_number = null;
                    var has_device_number_value = targetData.TryGetValue("@device_number", out device_number);
                    if (has_device_number_value)
                    {
                        object building_guid = null;
                        targetData.TryGetValue("@building_guid", out building_guid);
                        object main_system_guid = null;
                        targetData.TryGetValue("@main_system_guid", out main_system_guid);
                        object local_sub_system_guid = null;
                        targetData.TryGetValue("@sub_system_guid", out local_sub_system_guid);


                        foreach (var point in points)
                        {
                            Dictionary<string, object> insertDic = new Dictionary<string, object>()
                                {
                                    { "@building_guid", building_guid },
                                    { "@main_system_guid", main_system_guid },
                                    { "@sub_system_guid", local_sub_system_guid },
                                    { "@device_number", device_number },
                                    { "@name", point}
                                };

                            insertDics.Add(insertDic);

                            DeviceSubscrip deviceSubscrip = new DeviceSubscrip()
                            {
                                building_guid = building_guid.ToString(),
                                main_system_guid = main_system_guid.ToString(),
                                sub_system_guid = local_sub_system_guid.ToString(),
                                device_number = device_number.ToString(),
                            };

                            tempDeviceSubscrips.Add(deviceSubscrip);
                        }
                    }
                }

                List<string> properties = insertDics.First().Keys.ToList();
                string sql = InsertGenerateString(properties, "ontime_device_subscription");
                conn.Execute(sql, insertDics, trans);

                #region step 2 設定要訂閱的設備點位
                var subscripUriFormat = @" <uri val='/obix/config/Arena/{0}/{1}/{2}/out/' />";

                List<string> subscripStrings = new List<string>();

                foreach (var deviceSubscrip in insertDics)
                {
                    List<string> devicePaths = new List<string>();

                    object device_number = null;
                    var has_device_number = deviceSubscrip.TryGetValue("@device_number", out device_number);

                    //拆解設備編號來組出路徑
                    var deviceSubscripSplit = device_number.ToString().Split("_");
                    foreach (var temp in deviceSubscripSplit)
                    {
                        if (temp[0].ToString().All(char.IsDigit))
                        {
                            devicePaths.Add($"$3{temp}");
                        }
                        else
                        {
                            devicePaths.Add(temp);
                        }
                    }

                    //剔除最後一個,因為是設備名稱
                    devicePaths.RemoveAt(devicePaths.Count() - 1);

                    object point_name = null;
                    var has_point_name = deviceSubscrip.TryGetValue("@name", out point_name);

                    subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), device_number.ToString(), point_name.ToString()));
                }

                #endregion step 2 設定要訂閱的設備點位

                #region step 3 訂閱設備點位,並將回傳的值新增至資料庫
                EDFunction ed = new EDFunction();

                string userName = ed.AESDecrypt(_obixApiConfig.Value.UserName);
                string password = ed.AESDecrypt(_obixApiConfig.Value.Password);

                String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(userName + ":" + password));

                var sql_watch = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = @system_type AND system_key = @system_key";

                var watch = conn.QueryFirstOrDefault<Variable>(sql_watch, new { system_type = "obixConfig", system_key = "watch_id" });

                HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{_obixApiConfig.Value.ApiBase}obix/watchService/watch{watch.system_value}/add/");
                addWatchServiceRequest.Method = "POST";
                addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
                addWatchServiceRequest.PreAuthenticate = true;

                var subscripFullString = $@"<obj is='obix: WatchIn'>
                                                <list names = 'hrefs'>
                                                    {string.Join(null, subscripStrings)}
                                                </list>
                                            </obj>";
                byte[] byteArray = Encoding.UTF8.GetBytes(subscripFullString);
                using (Stream reqStream = addWatchServiceRequest.GetRequestStream())
                {
                    reqStream.Write(byteArray, 0, byteArray.Length);
                }

                HttpWebResponse addWatchServiceResponse = (HttpWebResponse)addWatchServiceRequest.GetResponse();
                var addWatchServiceResponseContent = new StreamReader(addWatchServiceResponse.GetResponseStream()).ReadToEnd();

                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(addWatchServiceResponseContent);
                string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
                JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson);

                if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤
                {
                    throw new NotImplementedException("設備點位訂閱失敗");

                    //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】");
                    //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】[錯誤內容]:{0}", addWatchServiceJsonResult);
                }

                if (addWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                {
                    List<Dictionary<string, object>> ontimeRawDatas = new List<Dictionary<string, object>>();

                    var ontimeList = addWatchServiceJsonResult["obj"]["list"];
                    if (ontimeList["real"] != null && ontimeList["real"].HasValues)
                    {
                        //讀取數值型
                        foreach (var real in ontimeList["real"])
                        {
                            var valueSplit = real["@display"].ToString().Split();
                            var value = valueSplit[0];
                            var href = real["@href"].ToString();
                            var hrefSplit = href.Split("/");
                            var findOutIndex = 0;
                            var outIndex = 0;
                            foreach (var tempHref in hrefSplit) //找出out的Index
                            {
                                if (tempHref == "out")
                                {
                                    outIndex = findOutIndex;
                                }
                                findOutIndex++;
                            }

                            var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號
                            var name = hrefSplit[outIndex - 1];//透過outIndex找出點位

                            var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();

                            Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
                            {
                                { "@building_guid", selectDevice.building_guid },
                                { "@main_system_guid", selectDevice.main_system_guid },
                                { "@sub_system_guid", selectDevice.sub_system_guid },
                                { "@device_number", device_number},
                                { "@name", name},
                                { "@value", value},
                                { "@is_bool", 0},
                            };

                            ontimeRawDatas.Add(ontimeRawData);
                        }
                    }

                    if (ontimeList["bool"] != null && ontimeList["bool"].HasValues)
                    {
                        //讀取布林型
                        foreach (var real in ontimeList["bool"])
                        {
                            var valueSplit = real["@display"].ToString().Split();
                            var value = valueSplit[0];
                            var href = real["@href"].ToString();
                            var hrefSplit = href.Split("/");
                            var findOutIndex = 0;
                            var outIndex = 0;
                            foreach (var tempHref in hrefSplit) //找出out的Index
                            {
                                if (tempHref == "out")
                                {
                                    outIndex = findOutIndex;
                                }
                                findOutIndex++;
                            }

                            var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號
                            var name = hrefSplit[outIndex - 1];//透過outIndex找出點位

                            var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();

                            Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
                            {
                                { "@building_guid", selectDevice.building_guid },
                                { "@main_system_guid", selectDevice.main_system_guid },
                                { "@sub_system_guid", selectDevice.sub_system_guid },
                                { "@device_number", device_number},
                                { "@name", name},
                                { "@value", value},
                                { "@is_bool", 1},
                            };

                            ontimeRawDatas.Add(ontimeRawData);
                        }
                    }

                    if (ontimeRawDatas.Count() > 0)
                    {
                        try
                        {
                            var insert_update_sql = $@"INSERT INTO ontime_device_rawdata (building_guid, main_system_guid, sub_system_guid, device_number, name, value, is_bool) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @value, @is_bool)
                                                    ON DUPLICATE KEY UPDATE value=@value, is_bool = @is_bool";
                            conn.Execute(insert_update_sql, ontimeRawDatas);
                        }
                        catch (Exception exception)
                        {
                            throw new NotImplementedException("新增設備點位原始資料失敗", exception);

                            //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】");
                            //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]:{0}", exception.ToString());
                        }
                    }

                    //logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務完成】");
                }

                #endregion step 3 訂閱設備點位,並將回傳的值新增至資料庫
            }
        }
    }
}