using Backend.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using Dapper;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Xml;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using Repository.Helper;
using Repository.BackendRepository.Interface;
using Repository.BackendRepository.Implement;
using System.Threading.Tasks;

namespace BackendWorkerService.Services.Implement
{
    /// <summary>
    /// 電錶補償歸檔
    /// </summary>
    public class ProcEletricMeterService
    {
        private readonly IBackgroundServiceRepository backgroundServiceRepository;
        private readonly IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository;

        public ProcEletricMeterService(IBackgroundServiceRepository backgroundServiceRepository,
            IBackgroundServiceMsSqlRepository backgroundServiceMySqlRepository)
        {
            this.backgroundServiceRepository = backgroundServiceRepository;
            this.backgroundServiceMsSqlRepository = backgroundServiceMySqlRepository;
        }

        public async Task<bool> ArchiveData()
        {
            bool result = false;
            int repeatTimes = 0;
            string targetTable = string.Empty;

            EDFunction ed = new EDFunction();
            XmlDocument xmlDocument = new XmlDocument();
            var obixApiConfig = new ObixApiConfig();
            string encoded = string.Empty;

            try
            {
                //取得可錯誤次數
                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);
                repeatTimes = Convert.ToInt32(variableArchive.Where(x => x.Name == "RepeatTimes").Select(x => x.Value).FirstOrDefault());

                #region 取得obix 設定
                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());

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

                //取得錯誤的設備sql format
                var sql_error_format = @"SELECT * FROM {0} WHERE is_complete = 0 AND repeat_times < @RepeatTimes";

                //MY 新增/修改sql format
                var MYsql_update_format = @"
                                            UPDATE {0} 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 {0} (
                                                    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;";
                //新增/修改sql format
                var sql_update_format = @"BEGIN TRANSACTION;

                                            UPDATE {0} 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 {0} (
                                                    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;";

                #region 時歸檔補償
                //using (IDbConnection conn = new SqlConnection(Connection1))
                //{
                //    //取得所有須補償的設備資訊
                //    targetTable = "archive_electric_meter_hour";
                //    var sql_error_hour = string.Format(sql_error_format, targetTable);
                //    var error_hours = conn.Query<ArchiveElectricMeter>(sql_error_hour, new { RepeatTimes = repeatTimes }).ToList();

                //    List<Dictionary<string, object>> archiveHourRawDatas = new List<Dictionary<string, object>>();
                //    if (error_hours.Count() > 0)
                //    {
                //        foreach (var error_hour in error_hours)
                //        {
                //            DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                //            deviceNumberPoint.DeviceNumber = error_hour.Device_number;
                //            deviceNumberPoint.Point = error_hour.Point;
                //            deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_hour.Device_number, error_hour.Point);

                //            var startTimestamp = string.Format("{0}+08:00", error_hour.Start_timestamp.Replace(" ", "T"));
                //            var endTimestamp = string.Format("{0}+08:00", error_hour.End_timestamp.Replace(" ", "T"));

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

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

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

                //            HttpWebResponse archiveHourResponse = (HttpWebResponse)archiveHourRequest.GetResponse();
                //            var archiveHourResponseContent = new StreamReader(archiveHourResponse.GetResponseStream()).ReadToEnd();

                //            xmlDocument.LoadXml(archiveHourResponseContent);
                //            string archiveHourJson = JsonConvert.SerializeXmlNode(xmlDocument);
                //            JObject archiveHourJsonResult = (JObject)JsonConvert.DeserializeObject(archiveHourJson);

                //            if (archiveHourJsonResult.ContainsKey("err")) //抓取錯誤
                //            {
                //                Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
                //                archiveDayRawData.Add("@device_number", error_hour.Device_number);
                //                archiveDayRawData.Add("@point", error_hour.Point);
                //                archiveDayRawData.Add("@start_timestamp", error_hour.Start_timestamp);
                //                archiveDayRawData.Add("@end_timestamp", error_hour.End_timestamp);
                //                archiveDayRawData.Add("@is_complete", 0);
                //                archiveDayRawData.Add("@repeat_times", ++error_hour.Repeat_times);
                //                archiveDayRawData.Add("@fail_reason", archiveHourJson);

                //                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"));

                //                archiveHourRawDatas.Add(archiveDayRawData);
                //            }

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

                //        if (archiveHourRawDatas.Count() > 0)
                //        {
                //            var sql_error_update = string.Format(sql_update_format, targetTable);
                //            conn.Execute(sql_error_update, archiveHourRawDatas);
                //        }
                //    }
                //    conn.Close();
                //}
                #endregion 時歸檔補償

                #region 天歸檔補償
                //取得所有須補償的設備資訊
                targetTable = "archive_electric_meter_day";
                var sql_error_day = string.Format(sql_error_format, targetTable);
                var error_days = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_day, new { RepeatTimes = repeatTimes });

                List<Dictionary<string, object>> archiveDayRawDatas = new List<Dictionary<string, object>>();
                if (error_days.Count() > 0)
                {
                    foreach (var error_day in error_days)
                    {
                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                        deviceNumberPoint.DeviceNumber = error_day.Device_number;
                        deviceNumberPoint.Point = error_day.Point;
                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_day.Device_number, error_day.Point);

                        var startTimestamp = string.Format("{0}+08:00", error_day.Start_timestamp.Replace(" ", "T"));
                        var endTimestamp = string.Format("{0}+08:00", error_day.End_timestamp.Replace(" ", "T"));

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

                        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")) //抓取錯誤
                        {
                            Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
                            archiveDayRawData.Add("@device_number", error_day.Device_number);
                            archiveDayRawData.Add("@point", error_day.Point);
                            archiveDayRawData.Add("@start_timestamp", DateTime.Parse(error_day.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveDayRawData.Add("@end_timestamp", DateTime.Parse(error_day.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveDayRawData.Add("@is_complete", 0);
                            archiveDayRawData.Add("@repeat_times", ++error_day.Repeat_times);
                            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"));

                            archiveDayRawDatas.Add(archiveDayRawData);
                        }

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

                    if (archiveDayRawDatas.Count() > 0)
                    {
                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
                        var sql_error_update = string.Format(sql_update_format, targetTable);
                        await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, archiveDayRawDatas);
                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, archiveDayRawDatas);
                    }
                }
                #endregion 天歸檔補償

                #region 週歸檔補償
                //取得所有須補償的設備資訊
                targetTable = "archive_electric_meter_week";
                var sql_error_week = string.Format(sql_error_format, targetTable);
                var error_weeks = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_week, new { RepeatTimes = repeatTimes });

                List<Dictionary<string, object>> archiveWeekRawDatas = new List<Dictionary<string, object>>();
                if (error_weeks.Count() > 0)
                {
                    foreach (var error_week in error_weeks)
                    {
                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                        deviceNumberPoint.DeviceNumber = error_week.Device_number;
                        deviceNumberPoint.Point = error_week.Point;
                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_week.Device_number, error_week.Point);

                        var startTimestamp = string.Format("{0}+08:00", error_week.Start_timestamp.Replace(" ", "T"));
                        var endTimestamp = string.Format("{0}+08:00", error_week.End_timestamp.Replace(" ", "T"));

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

                        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")) //抓取錯誤
                        {
                            Dictionary<string, object> archiveWeekRawData = new Dictionary<string, object>();
                            archiveWeekRawData.Add("@device_number", error_week.Device_number);
                            archiveWeekRawData.Add("@point", error_week.Point);
                            archiveWeekRawData.Add("@start_timestamp", DateTime.Parse(error_week.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveWeekRawData.Add("@end_timestamp", DateTime.Parse(error_week.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveWeekRawData.Add("@is_complete", 0);
                            archiveWeekRawData.Add("@repeat_times", ++error_week.Repeat_times);
                            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"));

                            archiveWeekRawDatas.Add(archiveWeekRawData);
                        }

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

                    if (archiveWeekRawDatas.Count() > 0)
                    {
                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
                        var sql_error_update = string.Format(sql_update_format, targetTable);
                        await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, archiveWeekRawDatas);
                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, archiveWeekRawDatas);
                    }
                }
                #endregion 週歸檔補償

                #region 月歸檔補償
                //取得所有須補償的設備資訊
                targetTable = "archive_electric_meter_month";
                var sql_error_month = string.Format(sql_error_format, targetTable);
                var error_months = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_month, new { RepeatTimes = repeatTimes });

                List<Dictionary<string, object>> archiveMonthRawDatas = new List<Dictionary<string, object>>();
                if (error_months.Count() > 0)
                {
                    foreach (var error_month in error_months)
                    {
                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
                        deviceNumberPoint.DeviceNumber = error_month.Device_number;
                        deviceNumberPoint.Point = error_month.Point;
                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_month.Device_number, error_month.Point);

                        var startTimestamp = string.Format("{0}+08:00", error_month.Start_timestamp.Replace(" ", "T"));
                        var endTimestamp = string.Format("{0}+08:00", error_month.End_timestamp.Replace(" ", "T"));

                        var startDateTime = Convert.ToDateTime(error_month.Start_timestamp);
                        var dayInMonth = DateTime.DaysInMonth(startDateTime.Year, startDateTime.Month);

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

                        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")) //抓取錯誤
                        {
                            Dictionary<string, object> archiveMonthRawData = new Dictionary<string, object>();
                            archiveMonthRawData.Add("@device_number", error_month.Device_number);
                            archiveMonthRawData.Add("@point", error_month.Point);
                            archiveMonthRawData.Add("@start_timestamp", DateTime.Parse(error_month.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveMonthRawData.Add("@end_timestamp", DateTime.Parse(error_month.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
                            archiveMonthRawData.Add("@is_complete", 0);
                            archiveMonthRawData.Add("@repeat_times", ++error_month.Repeat_times);
                            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"));

                            archiveMonthRawDatas.Add(archiveMonthRawData);
                        }

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

                    if (archiveMonthRawDatas.Count() > 0)
                    {
                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
                        var sql_error_update = string.Format(sql_update_format, targetTable);
                        await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, archiveMonthRawDatas);
                        await backgroundServiceRepository.ExecuteSql(MYsql_update_format, archiveMonthRawDatas);
                    }
                }
                #endregion 月歸檔補償

                result = true;
            }
            catch (Exception exception)
            {
                throw exception;
            }

            return result;
        }

        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 = Convert.ToDecimal(real["@val"].ToString());
                                        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 = Convert.ToDecimal(real["@val"].ToString());
                                    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;
        }
    }
}