using FrontendWebApi.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Repository.BackendRepository.Interface;
using Repository.FrontendRepository.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace FrontendWebApi.ApiControllers
{
    public class LightScheduleController : MyBaseApiController<LightScheduleController>
    {
        private readonly IBackendRepository backendRepository;
        private readonly IFrontendRepository frontendRepository;

        public LightScheduleController
        (
            IBackendRepository backendRepository,
            IFrontendRepository frontendRepository
        )
        {
            this.backendRepository = backendRepository;
            this.frontendRepository = frontendRepository;
        }

        [HttpPost]
        [Route("api/LightSchedule/GetLightDevice")]
        public async Task<ActionResult<ApiResult<List<lightDevice>>>> GetLightDevice(GetDevicePost post)
        {
            List<lightDevice> lightDevices = new List<lightDevice>();
            ApiResult<List<lightDevice>> apiResult = new ApiResult<List<lightDevice>>();
            try
            {
                var floor_tag = await backendRepository.GetOneAsync<string>($@"
                select full_name from floor where floor_guid = @floor_guid and deleted = 0
                ",new { floor_guid = post.floor_guid});

                lightDevices = await backendRepository.GetAllAsync<lightDevice>($@"
                select * from device where device_building_tag = '{post.building_tag}' and device_name_tag = '{post.sub_system_tag}' and device_floor_tag = '{floor_tag}' and deleted = 0 and status = 0 order by priority
                ");
                
                if(!String.IsNullOrEmpty(post.schedule_guid))
                {
                    var devicechecklist = await backendRepository.GetAllAsync<string>(@$"
                    select sd.device_guid from schedule_device sd where light_schedule_guid = '{post.schedule_guid}'
                    ");
                    foreach(var a in lightDevices)
                    {
                        if(devicechecklist.Contains(a.device_guid))
                        {
                            a.check = 1;
                        }
                        else
                        {
                            a.check = 0;
                        }
                    }
                }

                apiResult.Code = "0000";
                apiResult.Data = lightDevices;
            }
            catch (Exception exception)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
            }
            return Ok(apiResult);
        }

        [HttpPost]
        [Route("api/LightSchedule/SaveSchedule")]
        public async Task<ActionResult<ApiResult<string>>> SaveSchedule (SaveSchedule saveSchedule)
        {
            ApiResult<string> apiResult = new ApiResult<string>();
            try
            {
                // Operation_log 輸入參數
                OperationLog opeInput = new OperationLog() { operation_type = 2 };

                // 取得對應樓層資料
                var targetFloor = await backendRepository.GetOneAsync<Floor>($@"
                            select * from floor where floor_guid = @floor_guid",
                            new { floor_guid = saveSchedule.floor_guid});
                // 取得對應燈控排程主表資料
                var targetScheduleLight = await backendRepository.GetOneAsync<SaveSchedule>($@"
                            select * from light_schedule where light_schedule_guid = @light_schedule_guid",
                            new { light_schedule_guid = saveSchedule.light_schedule_guid });
                // 取得對應燈控排程設備資料
                var targetScheduleDevice = await backendRepository.GetAllAsync<string>($@"
                            select device_guid from schedule_device where light_schedule_guid = @light_schedule_guid",
                            new { light_schedule_guid = saveSchedule.light_schedule_guid });


                opeInput.building_tag = targetFloor.building_tag;
                opeInput.floor_tag = targetFloor.full_name;

                if (String.IsNullOrEmpty(saveSchedule.light_schedule_guid))
                {
                    opeInput.action_name = "新增";
                    Dictionary<string, object> Schedule = new Dictionary<string, object>();
                    var newguid = Guid.NewGuid();
                    Schedule = new Dictionary<string, object>()
                    {
                        { "@light_schedule_guid", newguid},
                        { "@status", saveSchedule.status},
                        { "@full_name", saveSchedule.full_name},
                        { "@week", saveSchedule.week},
                        { "@cycle", saveSchedule.cycle},
                        { "@floor_guid", saveSchedule.floor_guid},
                        { "@start_time", saveSchedule.start_time},
                        { "@end_time", saveSchedule.end_time},
                        { "@created_by", myUser.userinfo_guid}
                    };

                    await backendRepository.AddOneByCustomTable(Schedule, "light_schedule");
                    List<Dictionary<string, object>> ScheduleDevices = new List<Dictionary<string, object>>();
                    foreach (var a in saveSchedule.devicelist)
                    {
                        Dictionary<string, object> ScheduleDevice = new Dictionary<string, object>();
                        ScheduleDevice = new Dictionary<string, object>()
                        {
                            { "@light_schedule_guid", newguid},
                            { "@device_guid", a}
                        };
                        ScheduleDevices.Add(ScheduleDevice);
                    }
                    await backendRepository.AddMutiByCustomTable(ScheduleDevices, "schedule_device");
                    saveSchedule.light_schedule_guid = newguid.ToString();
                    opeInput.parameter = JsonConvert.SerializeObject(saveSchedule);
                    await InsertOperation(opeInput);
                }
                else
                {
                    opeInput.action_name = "修改";
                    Dictionary<string, object> Schedule = new Dictionary<string, object>();
                    Schedule = new Dictionary<string, object>()
                    {
                        { "@status", saveSchedule.status},
                        { "@full_name", saveSchedule.full_name},
                        { "@week", saveSchedule.week},
                        { "@cycle", saveSchedule.cycle},
                        { "@floor_guid", saveSchedule.floor_guid},
                        { "@start_time", saveSchedule.start_time},
                        { "@end_time", saveSchedule.end_time},
                        { "@updated_by", myUser.userinfo_guid},
                        { "@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}
                    };

                    // 比較欄位
                    List<string> compareTargetProps = new List<string>() { "full_name", "week", "cycle", "floor_guid", "start_time", "end_time" };
                    List<string> compareTargetValues = new List<string>();

                    Type modelType = saveSchedule.GetType();
                    // 根據每個欄位比較
                    foreach(var prop in compareTargetProps){
                        PropertyInfo propertyInfo = modelType.GetProperty(prop);
                        if (propertyInfo == null) continue;
                        // 比較 saveSchedule 與 targetSchedule
                        var value = propertyInfo.GetValue(saveSchedule,null)?.ToString();
                        var newValue = propertyInfo.GetValue(targetScheduleLight, null)?.ToString();
                        // 只要不對就是排程變更
                        if (value != newValue) {
                            saveSchedule.changeNames.Add("排程變更");
                            break;
                        }
                    }
                    // 判斷是否為狀態變更
                    if (targetScheduleLight.status != saveSchedule.status) {
                        saveSchedule.changeNames.Add("狀態變更");
                    }

                    // 兩邊設備 guid 排序後比較
                    saveSchedule.devicelist.Sort();
                    targetScheduleDevice.Sort();
                    if (!saveSchedule.devicelist.SequenceEqual(targetScheduleDevice)) {
                        saveSchedule.changeNames.Add("設備變更");
                    }

                    await backendRepository.UpdateOneByCustomTable(Schedule, "light_schedule", $" light_schedule_guid = '{saveSchedule.light_schedule_guid}'");
                    await backendRepository.PurgeOneByGuidWithCustomDBNameAndTable("schedule_device", $" light_schedule_guid = '{saveSchedule.light_schedule_guid}'");
                    List<Dictionary<string, object>> ScheduleDevices = new List<Dictionary<string, object>>();
                    foreach (var a in saveSchedule.devicelist)
                    {
                        Dictionary<string, object> ScheduleDevice = new Dictionary<string, object>();
                        ScheduleDevice = new Dictionary<string, object>()
                        {
                            { "@light_schedule_guid", saveSchedule.light_schedule_guid},
                            { "@device_guid", a}
                        };
                        ScheduleDevices.Add(ScheduleDevice);
                    }
                    await backendRepository.AddMutiByCustomTable(ScheduleDevices, "schedule_device");

                    opeInput.parameter = JsonConvert.SerializeObject(saveSchedule);
                    // 若有變更才寫入 operation_log
                    if (saveSchedule.changeNames.Count > 0) {
                        await InsertOperation(opeInput);
                    }
                }
                apiResult.Code = "0000";
                apiResult.Data = "成功";
            }
            catch (Exception exception)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
            }
            return Ok(apiResult);
        }


        [HttpPost]
        [Route("api/LightSchedule/ScheduleTable")]
        public async Task<ActionResult<ApiResult<List<ScheduleTable>>>> GetLightDevice(listfloors post)
        {
            List<ScheduleTable> ScheduleTable = new List<ScheduleTable>();
            ApiResult<List<ScheduleTable>> apiResult = new ApiResult<List<ScheduleTable>>();
            try
            {
                ScheduleTable = await backendRepository.GetAllAsync<ScheduleTable>($@"
                    select  ls.*,sd.devicecount from light_schedule ls
                    left join (select sd.light_schedule_guid, COUNT(*) devicecount from schedule_device sd group by sd.light_schedule_guid) sd on sd.light_schedule_guid = ls.light_schedule_guid
                    where ls.floor_guid in @floors and ls.deleted = 0
                    ",new { floors = post.Floors});
                apiResult.Code = "0000";
                apiResult.Data = ScheduleTable;
            }
            catch (Exception exception)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
            }
            return Ok(apiResult);
        }

        [HttpPost]
        [Route("api/LightSchedule/GetOneschedule")]
        public async Task<ActionResult<ApiResult<Schedule>>> GetOneschedule(string schedule_guid)
        {
            ApiResult<Schedule> apiResult = new ApiResult<Schedule>();
            try
            {
                var OneScheduleTable = await backendRepository.GetOneAsync<Schedule>($@"
                select * from light_schedule where light_schedule_guid = '{schedule_guid}'
                ");
                apiResult.Code = "0000";
                apiResult.Data = OneScheduleTable;
            }
            catch (Exception exception)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
            }
            return Ok(apiResult);
        }

        [HttpPost]
        [Route("api/LightSchedule/DeleteSchedule")]
        public async Task<ActionResult<ApiResult<string>>> DeleteSchedule(string schedule_guid)
        {
            ApiResult<string> apiResult = new ApiResult<string>();
            try
            {
                await backendRepository.DeleteOne(schedule_guid, "light_schedule", "light_schedule_guid");
                apiResult.Code = "0000";
            }
            catch (Exception ex)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + ex.Message);
            }
            return apiResult;
        }

        [HttpPost]
        [Route("api/LightSchedule/SendAPI")]
        public async Task<ActionResult<ApiResult<string>>> SendAPI(string guid)
        {
            ApiResult<string> apiResult = new ApiResult<string>();
            try
            {
                var TimeNow = DateTime.Now.ToString("dddd HH:mm");
                var oneSchedule = await backendRepository.GetOneAsync<Schedule>("light_schedule", $" light_schedule_guid = '{guid}'");
                var weeklistN = oneSchedule.week.Split(',');
                List<string> weeklist = new List<string>();
                foreach (var weekN in weeklistN)
                {
                    var week = weekN switch
                    {
                        "0" => "星期日",
                        "1" => "星期一",
                        "2" => "星期二",
                        "3" => "星期三",
                        "4" => "星期四",
                        "5" => "星期五",
                        "6" => "星期六",
                        _ => ""
                    };
                    weeklist.Add(week);
                }
                var Time = TimeNow.Split(" ");
                string check = "<real val='false' />";
                if(DateTime.Parse(Time[1])> DateTime.Parse(oneSchedule.start_time) && DateTime.Parse(Time[1]) <= DateTime.Parse(oneSchedule.end_time) && weeklist.Contains(Time[0]))
                {
                    check = "<real val='true' />";
                }
                else
                {
                    check = "<real val='false' />";
                }

                var deviceNumList = await backendRepository.GetAllAsync<string>(@$"select d.device_number from schedule_device sd left join device d on sd.device_guid = d.device_guid
                                                                                where light_schedule_guid = '{guid}'");

                foreach(var deviceNum in deviceNumList)
                {
                    var d = deviceNum.Split("_");
                    var html = "http://greencloud.fic.com.tw:8080/obix/config/Arena/"+$"{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set";
                    string authInfo = "AR_Light" + ":" + "Light12345";
                    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(html);
                    request.Method = "POST";
                    request.Accept = "application/json; charset=utf-8";
                    request.Headers["Authorization"] = "Basic " + authInfo;
                    byte[] byteArray = Encoding.UTF8.GetBytes(check);
                    using (Stream reqStream = request.GetRequestStream())
                    {
                        reqStream.Write(byteArray, 0, byteArray.Length);
                    }
                    var response = (HttpWebResponse)request.GetResponse();
                    string strResponse = "";

                    using (var sr = new StreamReader(response.GetResponseStream()))
                    {
                        strResponse = sr.ReadToEnd();
                    }
                }

                apiResult.Code = "0000";
            }
            catch (Exception ex)
            {
                apiResult.Code = "9999";
                apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
                Logger.LogError("【" + controllerName + "/" + actionName + "】" + ex.Message);
            }
            return Ok(apiResult);
        }

        public async Task<bool> InsertOperation(OperationLog input)
        {
            try
            {
                //記錄使用者操作紀錄
                Dictionary<string, object> userOperatorLog = new Dictionary<string, object>()
                        {
                            { "@user_guid", myUser.userinfo_guid },
                            { "@operation_type", input.operation_type }, //1:名稱修改
                            { "@building_tag", input.building_tag },
                            { "@main_system_tag", input.main_system_tag },
                            { "@sub_system_tag", input.sub_system_tag },
                            { "@floor_tag", input.floor_tag },
                            { "@device_guid", input.device_guid },
                            { "@action_name", input.action_name  },
                            { "@parameter", input.parameter },
                        };

                await backendRepository.AddOneByCustomTable(userOperatorLog, "operation_log");

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }
}