using Backend.Models;
using BackendWorkerService.Services.Implement;
using Dapper;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Quartz;
using Repository.BackendRepository.Interface;
using Repository.Helper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace BackendWorkerService.Quartz.Jobs
{
    [DisallowConcurrentExecution]
    class ArchiveElectricMeterDayJob : IJob
    {
        private readonly ILogger<ArchiveElectricMeterDayJob> logger;
        private readonly IBackgroundServiceRepository backgroundServiceRepository;
        private readonly IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository;
        protected readonly IDatabaseHelper _databaseHelper;
        private readonly ILogger<Task_Detail> loggers;


        public ArchiveElectricMeterDayJob(
            ILogger<ArchiveElectricMeterDayJob> logger,
            IBackgroundServiceRepository backgroundServiceRepository,
            IBackgroundServiceMsSqlRepository backgroundServiceMySqlRepository,
            IDatabaseHelper databaseHelper, ILogger<Task_Detail> loggers, IBackendRepository backendRepository)
        {
            this.logger = logger;
            this.backgroundServiceRepository = backgroundServiceRepository;
            this.backgroundServiceMsSqlRepository = backgroundServiceMySqlRepository;
            this._databaseHelper = databaseHelper;
            this.loggers = loggers;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            Task_Detail task_Detail = new Task_Detail(loggers, backgroundServiceRepository);
            try
            {
                if(await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "All"))
                {
                    await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "All", "任務開始");
                    EDFunction ed = new EDFunction();
                    XmlDocument xmlDocument = new XmlDocument();

                    var sqlArchive = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'archiveConfig'";

                    var variableArchive = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlArchive);
                    var electricMeterGuid = variableArchive.Where(x => x.Name == "ElectricMeterGuid").Select(x => x.Value).FirstOrDefault();
                    var waterMeterGuid = variableArchive.Where(x => x.Name == "WaterMeterGuid").Select(x => x.Value).FirstOrDefault();

                    #region 找出所有電錶設備
                    var sWhere = "deleted = 0 AND device_name_tag = @sub_system_guid";
                    var electricMeters = await backgroundServiceRepository.GetAllAsync<Device>("device", sWhere, new { sub_system_guid = electricMeterGuid });
                    var waterMeters = await backgroundServiceRepository.GetAllAsync<Device>("device", sWhere, new { sub_system_guid = waterMeterGuid });
                    #endregion 找出所有電錶設備

                    #region 找出所有電錶系統的點位
                    var sPointWhere = "deleted = 0 AND device_name_tag = @sub_system_guid";
                    var electricPoints = await backgroundServiceRepository.GetAllAsync<Device_item>("device_item", sPointWhere, new { sub_system_guid = electricMeterGuid });
                    var waterPoints = await backgroundServiceRepository.GetAllAsync<Device_item>("device_item", sPointWhere, new { sub_system_guid = waterMeterGuid });
                    #endregion 找出所有電錶系統的點位

                    #region 組合出所有電錶設備點位
                    List<DeviceNumberPoint> electricDeviceNumberPoints = new List<DeviceNumberPoint>();
                    foreach (var electricMeter in electricMeters)
                    {
                        foreach (var point in electricPoints)
                        {
                            DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                            deviceNumberPoint.DeviceNumber = electricMeter.Device_number;
                            deviceNumberPoint.Point = point.points;
                            deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", electricMeter.Device_number, point.points);

                            electricDeviceNumberPoints.Add(deviceNumberPoint);
                        }
                    }
                    #endregion 組合出所有電錶設備點位
                    #region 組合出所有水錶設備點位
                    List<DeviceNumberPoint> waterDeviceNumberPoints = new List<DeviceNumberPoint>();
                    foreach (var waterMeter in waterMeters)
                    {
                        foreach (var point in waterPoints)
                        {
                            DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                            deviceNumberPoint.DeviceNumber = waterMeter.Device_number;
                            deviceNumberPoint.Point = point.points;
                            deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", waterMeter.Device_number, point.points);

                            waterDeviceNumberPoints.Add(deviceNumberPoint);
                        }
                    }
                    #endregion 組合出所有電錶設備點位

                    #region 取得obix 設定
                    var obixApiConfig = new ObixApiConfig();

                    var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'";

                    var variableObix = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlObix);
                    obixApiConfig.ApiBase = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
                    obixApiConfig.UserName = ed.AESDecrypt(variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault());
                    obixApiConfig.Password = ed.AESDecrypt(variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault());

                    String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password));
                    #endregion 取得obix 設定

                    var now = DateTime.Now;

                    #region 天歸檔
                    if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Day"))
                    {
                        try
                        {
                            await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Day", "任務開始");
                            var preDay = now.AddDays(-1); //取得前一天

                            var startTimestamp = string.Format("{0}T00:00:00.000+08:00", preDay.ToString("yyyy-MM-dd"));
                            var endTimestamp = string.Format("{0}T23:59:59.000+08:00", preDay.ToString("yyyy-MM-dd"));

                            var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
                                                    <abstime name='start' val='{startTimestamp}' />
                                                    <abstime name='end' val='{endTimestamp}' />
                                                    <reltime name='interval' val = 'PT1D' />
                                                </obj>";

                            //Stopwatch stopWatch = new Stopwatch();
                            //stopWatch.Start();

                            //抓取每個設備的資料
                            List<Dictionary<string, object>> electericArchiveDayRawDatas = new List<Dictionary<string, object>>();
                            List<Dictionary<string, object>> waterArchiveDayRawDatas = new List<Dictionary<string, object>>();
                            foreach (var deviceNumberPoint in electricDeviceNumberPoints)
                            {

                                HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveDayRequest.Method = "POST";
                                archiveDayRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveDayRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveDayRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveDayResponse = (HttpWebResponse)archiveDayRequest.GetResponse();
                                var archiveDayResponseContent = new StreamReader(archiveDayResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveDayResponseContent);
                                string archiveDayJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveDayJsonResult = (JObject)JsonConvert.DeserializeObject(archiveDayJson);

                                if (archiveDayJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveDayJsonResult);

                                    Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
                                    archiveDayRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveDayRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveDayRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveDayRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveDayRawData.Add("@is_complete", 0);
                                    archiveDayRawData.Add("@repeat_times", 0);
                                    archiveDayRawData.Add("@fail_reason", archiveDayJson);

                                    archiveDayRawData.Add("@count_rawdata", 0);
                                    archiveDayRawData.Add("@min_rawdata", 0);
                                    archiveDayRawData.Add("@max_rawdata", 0);
                                    archiveDayRawData.Add("@avg_rawdata", 0);
                                    archiveDayRawData.Add("@sum_rawdata", 0);
                                    archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    electericArchiveDayRawDatas.Add(archiveDayRawData);
                                }

                                if (archiveDayJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveDayJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        electericArchiveDayRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }
                            foreach (var deviceNumberPoint in waterDeviceNumberPoints)
                            {

                                HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveDayRequest.Method = "POST";
                                archiveDayRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveDayRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveDayRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveDayResponse = (HttpWebResponse)archiveDayRequest.GetResponse();
                                var archiveDayResponseContent = new StreamReader(archiveDayResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveDayResponseContent);
                                string archiveDayJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveDayJsonResult = (JObject)JsonConvert.DeserializeObject(archiveDayJson);

                                if (archiveDayJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveDayJsonResult);

                                    Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
                                    archiveDayRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveDayRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveDayRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveDayRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveDayRawData.Add("@is_complete", 0);
                                    archiveDayRawData.Add("@repeat_times", 0);
                                    archiveDayRawData.Add("@fail_reason", archiveDayJson);

                                    archiveDayRawData.Add("@count_rawdata", 0);
                                    archiveDayRawData.Add("@min_rawdata", 0);
                                    archiveDayRawData.Add("@max_rawdata", 0);
                                    archiveDayRawData.Add("@avg_rawdata", 0);
                                    archiveDayRawData.Add("@sum_rawdata", 0);
                                    archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    waterArchiveDayRawDatas.Add(archiveDayRawData);
                                }

                                if (archiveDayJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveDayJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        waterArchiveDayRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }

                            //stopWatch.Stop();
                            //logger.LogInformation("【ArchiveElectricMeterDayJob】【天歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds);

                            if (electericArchiveDayRawDatas.Count() > 0)
                            {
                                var sql = $@"
                                            UPDATE archive_electric_meter_day SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            
                                            INSERT INTO archive_electric_meter_day (
                                                device_number,
                                                point,
                                                start_timestamp,
                                                end_timestamp,
                                                count_rawdata,
                                                min_rawdata,
                                                max_rawdata,
                                                avg_rawdata,
                                                sum_rawdata,
                                                is_complete,
                                                repeat_times,
                                                fail_reason)
                                            SELECT 
                                                @device_number,
                                                @point,
                                                @start_timestamp,
                                                @end_timestamp,
                                                @count_rawdata,
                                                @min_rawdata,
                                                @max_rawdata,
                                                @avg_rawdata,
                                                @sum_rawdata,
                                                @is_complete,
                                                @repeat_times,
                                                @fail_reason
                                            WHERE ROW_COUNT() = 0;";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_electric_meter_day SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_electric_meter_day (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, electericArchiveDayRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electericArchiveDayRawDatas);
                            }
                            if (waterArchiveDayRawDatas.Count() > 0)
                            {
                                var sql = $@"
                                            UPDATE archive_water_meter_day SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            
                                            INSERT INTO archive_water_meter_day (
                                                device_number,
                                                point,
                                                start_timestamp,
                                                end_timestamp,
                                                count_rawdata,
                                                min_rawdata,
                                                max_rawdata,
                                                avg_rawdata,
                                                sum_rawdata,
                                                is_complete,
                                                repeat_times,
                                                fail_reason)
                                            SELECT 
                                                @device_number,
                                                @point,
                                                @start_timestamp,
                                                @end_timestamp,
                                                @count_rawdata,
                                                @min_rawdata,
                                                @max_rawdata,
                                                @avg_rawdata,
                                                @sum_rawdata,
                                                @is_complete,
                                                @repeat_times,
                                                @fail_reason
                                            WHERE ROW_COUNT() = 0;";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_water_meter_day SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_water_meter_day (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, waterArchiveDayRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveDayRawDatas);
                            }
                            await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Day", "任務完成");
                        }
                        catch (Exception exception)
                        {
                            await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Day", exception.ToString());
                            logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【任務失敗】");
                            logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【任務失敗】[Exception]:{0}", exception.ToString());
                        }
                    }
                    #endregion 天歸檔

                    #region 週歸檔
                    if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Week"))
                    {
                        try
                        {
                            await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Week", "任務開始");
                            int week = Convert.ToInt32(now.DayOfWeek);
                            week = week == 0 ? 7 : week;

                            var startTimestamp = string.Format("{0}T00:00:00.000+08:00", now.AddDays(1 - week).ToString("yyyy-MM-dd"));
                            var endTimestamp = string.Format("{0}T23:59:59.000+08:00", now.AddDays(7 - week).ToString("yyyy-MM-dd"));

                            var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
                                                    <abstime name='start' val='{startTimestamp}' />
                                                    <abstime name='end' val='{endTimestamp}' />
                                                    <reltime name='interval' val = 'PT7D' />
                                                </obj>";

                            //Stopwatch stopWatch = new Stopwatch();
                            //stopWatch.Start();

                            //抓取每個設備的資料
                            List<Dictionary<string, object>> electricArchiveWeekRawDatas = new List<Dictionary<string, object>>();
                            List<Dictionary<string, object>> waterArchiveWeekRawDatas = new List<Dictionary<string, object>>();
                            foreach (var deviceNumberPoint in electricDeviceNumberPoints)
                            {
                                HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveWeekRequest.Method = "POST";
                                archiveWeekRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveWeekRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveWeekRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveWeekResponse = (HttpWebResponse)archiveWeekRequest.GetResponse();
                                var archiveWeekResponseContent = new StreamReader(archiveWeekResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveWeekResponseContent);
                                string archiveWeekJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveWeekJsonResult = (JObject)JsonConvert.DeserializeObject(archiveWeekJson);

                                if (archiveWeekJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveWeekJsonResult);

                                    Dictionary<string, object> archiveWeekRawData = new Dictionary<string, object>();
                                    archiveWeekRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveWeekRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveWeekRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveWeekRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveWeekRawData.Add("@is_complete", 0);
                                    archiveWeekRawData.Add("@repeat_times", 0);
                                    archiveWeekRawData.Add("@fail_reason", archiveWeekJson);

                                    archiveWeekRawData.Add("@count_rawdata", 0);
                                    archiveWeekRawData.Add("@min_rawdata", 0);
                                    archiveWeekRawData.Add("@max_rawdata", 0);
                                    archiveWeekRawData.Add("@avg_rawdata", 0);
                                    archiveWeekRawData.Add("@sum_rawdata", 0);
                                    archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    electricArchiveWeekRawDatas.Add(archiveWeekRawData);
                                }

                                if (archiveWeekJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveWeekJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        electricArchiveWeekRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }
                            foreach (var deviceNumberPoint in waterDeviceNumberPoints)
                            {
                                HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveWeekRequest.Method = "POST";
                                archiveWeekRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveWeekRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveWeekRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveWeekResponse = (HttpWebResponse)archiveWeekRequest.GetResponse();
                                var archiveWeekResponseContent = new StreamReader(archiveWeekResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveWeekResponseContent);
                                string archiveWeekJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveWeekJsonResult = (JObject)JsonConvert.DeserializeObject(archiveWeekJson);

                                if (archiveWeekJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveWeekJsonResult);

                                    Dictionary<string, object> archiveWeekRawData = new Dictionary<string, object>();
                                    archiveWeekRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveWeekRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveWeekRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveWeekRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveWeekRawData.Add("@is_complete", 0);
                                    archiveWeekRawData.Add("@repeat_times", 0);
                                    archiveWeekRawData.Add("@fail_reason", archiveWeekJson);

                                    archiveWeekRawData.Add("@count_rawdata", 0);
                                    archiveWeekRawData.Add("@min_rawdata", 0);
                                    archiveWeekRawData.Add("@max_rawdata", 0);
                                    archiveWeekRawData.Add("@avg_rawdata", 0);
                                    archiveWeekRawData.Add("@sum_rawdata", 0);
                                    archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    waterArchiveWeekRawDatas.Add(archiveWeekRawData);
                                }

                                if (archiveWeekJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveWeekJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        waterArchiveWeekRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }

                            //stopWatch.Stop();
                            //logger.LogInformation("【ArchiveElectricMeterDayJob】【週歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds);

                            if (electricArchiveWeekRawDatas.Count() > 0)
                            {
                                var sql = $@"

                                            UPDATE archive_electric_meter_week SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;


                                                INSERT INTO archive_electric_meter_week (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                SELECT 
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason
                                                WHERE ROW_COUNT() = 0;
                                                ";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_electric_meter_week SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_electric_meter_week (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, electricArchiveWeekRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electricArchiveWeekRawDatas);

                            }
                            if (waterArchiveWeekRawDatas.Count() > 0)
                            {
                                var sql = $@"

                                            UPDATE archive_water_meter_week SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;


                                                INSERT INTO archive_water_meter_week (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                SELECT 
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason
                                                WHERE ROW_COUNT() = 0;
                                                ";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_water_meter_week SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_water_meter_week (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, waterArchiveWeekRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveWeekRawDatas);

                            }
                            await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Week", "任務完成");
                        }
                        catch (Exception exception)
                        {
                            await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Week", exception.ToString());
                            logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【任務失敗】");
                            logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【任務失敗】[Exception]:{0}", exception.ToString());
                        }
                    }
                    #endregion 週歸檔

                    #region 月歸檔
                    if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Month"))
                    {
                        try
                        {
                            await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Month", "任務開始");
                            var FirstDay = now.AddDays(-now.Day + 1);
                            var LastDay = now.AddMonths(1).AddDays(-now.AddMonths(1).Day);

                            var dayInMonth = DateTime.DaysInMonth(now.Year, now.Month);

                            var startTimestamp = string.Format("{0}T00:00:00.000+08:00", FirstDay.ToString("yyyy-MM-dd"));
                            var endTimestamp = string.Format("{0}T23:59:59.000+08:00", LastDay.ToString("yyyy-MM-dd"));

                            var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
                                                    <abstime name='start' val='{startTimestamp}' />
                                                    <abstime name='end' val='{endTimestamp}' />
                                                    <reltime name='interval' val = 'PT{dayInMonth}D' />
                                                </obj>";

                            //Stopwatch stopWatch = new Stopwatch();
                            //stopWatch.Start();

                            //抓取每個設備的資料
                            List<Dictionary<string, object>> electricArchiveMonthRawDatas = new List<Dictionary<string, object>>();
                            List<Dictionary<string, object>> waterArchiveMonthRawDatas = new List<Dictionary<string, object>>();
                            foreach (var deviceNumberPoint in electricDeviceNumberPoints)
                            {
                                HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveMonthRequest.Method = "POST";
                                archiveMonthRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveMonthRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveMonthRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveMonthResponse = (HttpWebResponse)archiveMonthRequest.GetResponse();
                                var archiveMonthResponseContent = new StreamReader(archiveMonthResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveMonthResponseContent);
                                string archiveMonthJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveMonthJsonResult = (JObject)JsonConvert.DeserializeObject(archiveMonthJson);

                                if (archiveMonthJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveMonthJsonResult);

                                    Dictionary<string, object> archiveMonthRawData = new Dictionary<string, object>();
                                    archiveMonthRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveMonthRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveMonthRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveMonthRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveMonthRawData.Add("@is_complete", 0);
                                    archiveMonthRawData.Add("@repeat_times", 0);
                                    archiveMonthRawData.Add("@fail_reason", archiveMonthJson);

                                    archiveMonthRawData.Add("@count_rawdata", 0);
                                    archiveMonthRawData.Add("@min_rawdata", 0);
                                    archiveMonthRawData.Add("@max_rawdata", 0);
                                    archiveMonthRawData.Add("@avg_rawdata", 0);
                                    archiveMonthRawData.Add("@sum_rawdata", 0);
                                    archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    electricArchiveMonthRawDatas.Add(archiveMonthRawData);
                                }

                                if (archiveMonthJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveMonthJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        electricArchiveMonthRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }
                            foreach (var deviceNumberPoint in waterDeviceNumberPoints)
                            {
                                HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
                                //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
                                archiveMonthRequest.Method = "POST";
                                archiveMonthRequest.Headers.Add("Authorization", "Basic " + encoded);
                                archiveMonthRequest.PreAuthenticate = true;

                                byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
                                using (Stream reqStream = archiveMonthRequest.GetRequestStream())
                                {
                                    reqStream.Write(byteArray, 0, byteArray.Length);
                                }

                                HttpWebResponse archiveMonthResponse = (HttpWebResponse)archiveMonthRequest.GetResponse();
                                var archiveMonthResponseContent = new StreamReader(archiveMonthResponse.GetResponseStream()).ReadToEnd();

                                xmlDocument.LoadXml(archiveMonthResponseContent);
                                string archiveMonthJson = JsonConvert.SerializeXmlNode(xmlDocument);
                                JObject archiveMonthJsonResult = (JObject)JsonConvert.DeserializeObject(archiveMonthJson);

                                if (archiveMonthJsonResult.ContainsKey("err")) //抓取錯誤
                                {
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】");
                                    //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveMonthJsonResult);

                                    Dictionary<string, object> archiveMonthRawData = new Dictionary<string, object>();
                                    archiveMonthRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                                    archiveMonthRawData.Add("@point", deviceNumberPoint.Point);
                                    archiveMonthRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveMonthRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
                                    archiveMonthRawData.Add("@is_complete", 0);
                                    archiveMonthRawData.Add("@repeat_times", 0);
                                    archiveMonthRawData.Add("@fail_reason", archiveMonthJson);

                                    archiveMonthRawData.Add("@count_rawdata", 0);
                                    archiveMonthRawData.Add("@min_rawdata", 0);
                                    archiveMonthRawData.Add("@max_rawdata", 0);
                                    archiveMonthRawData.Add("@avg_rawdata", 0);
                                    archiveMonthRawData.Add("@sum_rawdata", 0);
                                    archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                                    waterArchiveMonthRawDatas.Add(archiveMonthRawData);
                                }

                                if (archiveMonthJsonResult.ContainsKey("obj")) //表示可以讀取到內容
                                {
                                    var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveMonthJsonResult);
                                    if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
                                    {
                                        waterArchiveMonthRawDatas.AddRange(ArrangeRawDatas);
                                    }
                                }
                            }

                            //stopWatch.Stop();
                            //logger.LogInformation("【ArchiveElectricMeterDayJob】【月歸檔效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds);

                            if (electricArchiveMonthRawDatas.Count() > 0)
                            {
                                var sql = $@"
                                            UPDATE archive_electric_meter_month SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                                INSERT INTO archive_electric_meter_month (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                SELECT
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason
                                                WHERE ROW_COUNT() = 0;";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_electric_meter_month SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_electric_meter_month (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, electricArchiveMonthRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electricArchiveMonthRawDatas);
                            }
                            if (waterArchiveMonthRawDatas.Count() > 0)
                            {
                                var sql = $@"
                                            UPDATE archive_water_meter_month SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                                INSERT INTO archive_water_meter_month (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                SELECT
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason
                                                WHERE ROW_COUNT() = 0;";

                                var mySql = $@"BEGIN TRANSACTION;

                                            UPDATE archive_water_meter_month SET 
                                                    count_rawdata = @count_rawdata,
                                                    min_rawdata = @min_rawdata,
                                                    max_rawdata = @max_rawdata,
                                                    avg_rawdata = @avg_rawdata,
                                                    sum_rawdata = @sum_rawdata,
                                                    is_complete = @is_complete,
                                                    repeat_times = @repeat_times,
                                                    fail_reason = @fail_reason,
                                                    updated_at = @updated_at
                                                 WHERE device_number = @device_number
                                                    AND point = @point
                                                    AND start_timestamp = @start_timestamp;

                                            IF @@ROWCOUNT = 0
                                            BEGIN
                                                INSERT INTO archive_water_meter_month (
                                                    device_number,
                                                    point,
                                                    start_timestamp,
                                                    end_timestamp,
                                                    count_rawdata,
                                                    min_rawdata,
                                                    max_rawdata,
                                                    avg_rawdata,
                                                    sum_rawdata,
                                                    is_complete,
                                                    repeat_times,
                                                    fail_reason)
                                                VALUES (
                                                    @device_number,
                                                    @point,
                                                    @start_timestamp,
                                                    @end_timestamp,
                                                    @count_rawdata,
                                                    @min_rawdata,
                                                    @max_rawdata,
                                                    @avg_rawdata,
                                                    @sum_rawdata,
                                                    @is_complete,
                                                    @repeat_times,
                                                    @fail_reason)
                                            END

                                        COMMIT TRANSACTION;";
                                await backgroundServiceRepository.ExecuteSql(sql, waterArchiveMonthRawDatas);
                                await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveMonthRawDatas);
                            }
                            await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Month", "任務完成");
                        }
                        catch (Exception exception)
                        {
                            await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Month", exception.ToString());
                            logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【任務失敗】");
                            logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【任務失敗】[Exception]:{0}", exception.ToString());
                        }
                    }
                    #endregion 月歸檔

                    #region 補償機制
                    //取得連線字串
                    if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Compensate"))
                    {
                        try
                        {
                            await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Compensate", "任務開始");
                            ProcEletricMeterService procEletricMeterService = new ProcEletricMeterService(backgroundServiceRepository, backgroundServiceMsSqlRepository);
                            await procEletricMeterService.ArchiveData();
                            await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Compensate", "任務完成");
                        }
                        catch(Exception ex)
                        {
                            await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Compensate", ex.ToString());
                            logger.LogError("【ArchiveElectricMeterDayJob】【補償機制】【任務失敗】");
                            logger.LogError("【ArchiveElectricMeterDayJob】【補償機制】【任務失敗】[Exception]:{0}", ex.ToString());
                        }
                    }
                    #endregion 補償機制

                    await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "All","任務完成");
                }
            }
            catch (Exception exception)
            {
                await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "All", exception.ToString());
                logger.LogError("【ArchiveElectricMeterDayJob】【任務失敗】");
                logger.LogError("【ArchiveElectricMeterDayJob】【任務失敗】[Exception]:{0}", exception.ToString());
            }
        }

        private List<Dictionary<string, object>> ArrangeRawData(DeviceNumberPoint deviceNumberPoint, JObject jsonResult)
        {
            List<Dictionary<string, object>> arrangeRawDatas = new List<Dictionary<string, object>>();
            var histories = jsonResult["obj"]["list"];
            var rawdateCount = Convert.ToInt32(jsonResult["obj"]["int"]["@val"].ToString());

            if(rawdateCount == 0)
            {
                return null;
            }

            if (histories != null && histories.HasValues)
            {
                if (rawdateCount > 1)
                {   //多筆資料
                    foreach (var history in histories)
                    {
                        Dictionary<string, object> arrangeRawData = new Dictionary<string, object>();
                        arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                        arrangeRawData.Add("@point", deviceNumberPoint.Point);

                        //時間
                        if (history["abstime"] != null && history["abstime"].HasValues)
                        {
                            foreach (var abstime in history["abstime"])
                            {
                                var name = abstime["@name"].ToString();
                                switch (name)
                                {
                                    case "start":
                                        var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
                                        arrangeRawData.Add("@start_timestamp", startTimstamp);
                                        break;
                                    case "end":
                                        var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
                                        arrangeRawData.Add("@end_timestamp", endTimstamp);
                                        break;
                                }
                            }
                        }

                        //區間內資料筆數
                        if (history["int"] != null && history["int"].HasValues)
                        {
                            var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
                            arrangeRawData.Add("@count_rawdata", count);
                        }

                        //整合數值(最大、最小、平均、總和)
                        if (history["real"] != null && history["real"].HasValues)
                        {
                            foreach (var real in history["real"])
                            {
                                var name = real["@name"].ToString();
                                switch (name)
                                {
                                    case "min":
                                        var min = Convert.ToDecimal(real["@val"].ToString());
                                        arrangeRawData.Add("@min_rawdata", min);
                                        break;
                                    case "max":
                                        var max = Convert.ToDecimal(real["@val"].ToString());
                                        arrangeRawData.Add("@max_rawdata", max);
                                        break;
                                    case "avg":
                                        var avg = Convert.ToDecimal(real["@val"].ToString());
                                        arrangeRawData.Add("@avg_rawdata", avg);
                                        break;
                                    case "sum":
                                        var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float);
                                        arrangeRawData.Add("@sum_rawdata", sum);
                                        break;
                                }
                            }
                        }
                        arrangeRawData.Add("@is_complete", 1);
                        arrangeRawData.Add("@repeat_times", 0);
                        arrangeRawData.Add("@fail_reason", null);
                        arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                        arrangeRawDatas.Add(arrangeRawData);
                    }
                }
                else
                {   //單筆資料
                    Dictionary<string, object> arrangeRawData = new Dictionary<string, object>();
                    arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
                    arrangeRawData.Add("@point", deviceNumberPoint.Point);

                    //時間
                    if (histories["obj"]["abstime"] != null && histories["obj"]["abstime"].HasValues)
                    {
                        foreach (var abstime in histories["obj"]["abstime"])
                        {
                            var name = abstime["@name"].ToString();
                            switch (name)
                            {
                                case "start":
                                    var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
                                    arrangeRawData.Add("@start_timestamp", startTimstamp);
                                    break;
                                case "end":
                                    var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
                                    arrangeRawData.Add("@end_timestamp", endTimstamp);
                                    break;
                            }
                        }
                    }

                    //區間內資料筆數
                    if (histories["obj"]["int"] != null && histories["obj"]["int"].HasValues)
                    {
                        var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
                        arrangeRawData.Add("@count_rawdata", count);
                    }

                    //整合數值(最大、最小、平均、總和)
                    if (histories["obj"]["real"] != null && histories["obj"]["real"].HasValues)
                    {
                        foreach (var real in histories["obj"]["real"])
                        {
                            var name = real["@name"].ToString();
                            switch (name)
                            {
                                case "min":
                                    var min = Convert.ToDecimal(real["@val"].ToString());
                                    arrangeRawData.Add("@min_rawdata", min);
                                    break;
                                case "max":
                                    var max = Convert.ToDecimal(real["@val"].ToString());
                                    arrangeRawData.Add("@max_rawdata", max);
                                    break;
                                case "avg":
                                    var avg = Convert.ToDecimal(real["@val"].ToString());
                                    arrangeRawData.Add("@avg_rawdata", avg);
                                    break;
                                case "sum":
                                    var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float);
                                    arrangeRawData.Add("@sum_rawdata", sum);
                                    break;
                            }
                        }
                    }
                    arrangeRawData.Add("@is_complete", 1);
                    arrangeRawData.Add("@repeat_times", 0);
                    arrangeRawData.Add("@fail_reason", null);
                    arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

                    arrangeRawDatas.Add(arrangeRawData);
                }
            }

            return arrangeRawDatas;
        }
    }
}