using DeviceRepair.Models;
using DeviceRepair.Models.Common;
using DeviceRepair.Models.Device;
using DeviceRepair.Models.Enum;
using DeviceRepair.Models.Plan;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace DeviceRepair.DataAccess
{
    public class PlanAccess : DbContext<DriveMaintencePlanInfo>
    {
        private static PlanAccess manager;
        public static PlanAccess Instance
        {
            get
            {
                if (manager == null)
                    manager = new PlanAccess();
                return manager;
            }
        }

        /// <summary>
        /// 保养计划批量新增数据
        /// </summary>
        /// <param name="lst"></param>
        /// <returns></returns>
        public APIResponseData InsertDatas(List<DriveMaintencePlanInfo> lst, HeaderModel hm)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"新增失败或当前数据无更改，请重试！" };
            try
            {
                db.ChangeDatabase("main");
                DateTime CurrentTime = DateTime.Now;
                if (lst == null || lst.Count == 0)
                    throw new Exception("插入的数据集合,不能为空！");

                // 操作对象
                Dictionary<EnumOperationType, List<DriveMaintencePlanInfo>> OperationList = new Dictionary<EnumOperationType, List<DriveMaintencePlanInfo>>();
                OperationList.Add(EnumOperationType.Add, new List<DriveMaintencePlanInfo>());
                OperationList.Add(EnumOperationType.Change, new List<DriveMaintencePlanInfo>());

                db.BeginTran();
                int Year = lst[0].MaintenanceYear;
                int[] equipmentIds = lst.Select(x => x.EquipmentID).Distinct().ToArray();

                // 设备编号校验
                Dictionary<int, DeviceInformationInfo> devs =
                    DeviceAccess.Instance.CurrentDb.AsQueryable().With(SqlWith.NoLock).Where(x => SqlFunc.ContainsArray(equipmentIds, x.AutoID)).ToList().ToDictionary(x => x.AutoID, x => x);

                System.Text.StringBuilder builder = new System.Text.StringBuilder();
                foreach (int id in equipmentIds)
                {
                    if (!devs.ContainsKey(id))
                    {
                        builder.AppendLine($"设备编号：{id} ,不存在于系统中！");
                    }
                }

                if (builder.Length > 0)
                    throw new Exception(builder.ToString());

                // 计划校验
                List<DriveMaintencePlanInfo> Plans = CurrentDb.AsQueryable()
                    .With(SqlWith.NoLock).Where(x => SqlFunc.ContainsArray(equipmentIds, x.EquipmentID) && x.MaintenanceYear == Year).ToList();
                int[] planIds = Plans.Select(x => x.AutoID).Distinct().ToArray();

                // 已保养数据不允许修改
                List<MaintenanceRecordInfo> Records = db.Queryable<MaintenanceRecordInfo>().Where(x => SqlFunc.ContainsArray(planIds, x.PlanPrimaryID)).ToList();
                foreach (MaintenanceRecordInfo item in Records)
                {
                    DriveMaintencePlanInfo t = Plans.FirstOrDefault(x => x.AutoID == item.PlanPrimaryID);
                    if (t != null)
                    {
                        DriveMaintencePlanInfo tt = lst.FirstOrDefault(x => x.MaintenanceMonth == t.MaintenanceMonth && x.EquipmentID == t.EquipmentID);
                        if (tt != null)
                        {
                            // 计划已保养，但本次操作未修改此条保养的数据，正常执行
                            if (tt.MaintenanceType == t.MaintenanceType)
                            {
                                lst.RemoveAll(x => x.MaintenanceType == t.MaintenanceType && x.MaintenanceMonth == t.MaintenanceMonth && x.EquipmentID == t.EquipmentID);
                            }
                            else
                            {
                                // 计划已保养且本次欲修改此数据，退出保养
                                builder.AppendLine($"设备编号：{devs[t.EquipmentID].EquipmentID} 在{t.MaintenanceMonth}月的计划，存在已保养的数据，无法更改！");
                            }
                        }
                    }
                }

                if (builder.Length > 0)
                    throw new Exception(builder.ToString());

                // 修改的计划
                List<int> DelPlanIds = new List<int>();
                foreach (DriveMaintencePlanInfo item in Plans)
                {
                    // 取数据库计划信息，对应当前传入的计划
                    DriveMaintencePlanInfo t = lst.FirstOrDefault(x => x.MaintenanceMonth == item.MaintenanceMonth && x.EquipmentID == item.EquipmentID);

                    if (t != null && ((t.MaintenanceType != item.MaintenanceType) || t.PMStartMonth != item.PMStartMonth || t.Remarks != item.Remarks))
                    {
                        // 修改的数据
                        item.ChangeDate = CurrentTime;
                        item.ChangeUser = hm.Operator;
                        item.MaintenanceType = t.MaintenanceType;
                        item.PMStartMonth = t.PMStartMonth;
                        item.Remarks = t.Remarks;
                        OperationList[EnumOperationType.Change].Add(item);
                    }
                }

                // 新增的计划
                int[] EditEquipmentIds = OperationList[EnumOperationType.Change].Select(x => x.EquipmentID).Distinct().ToArray();
                List<DriveMaintencePlanInfo> InPlans = lst.Where(x => x.MaintenanceYear == Year && !EditEquipmentIds.Contains(x.EquipmentID)).ToList();
                foreach (DriveMaintencePlanInfo item in InPlans)
                {
                    item.CreatDate = CurrentTime;
                    item.CreatUser = hm.Operator;

                    OperationList[EnumOperationType.Add].Add(item);
                }


                // 存在新增项
                List<DriveMaintencePlanInfo> FulfillmentLst = new List<DriveMaintencePlanInfo>();
                FulfillmentLst.AddRange(OperationList[EnumOperationType.Add]);
                FulfillmentLst.AddRange(OperationList[EnumOperationType.Change]);


                if (db.Saveable(FulfillmentLst).ExecuteCommand() == FulfillmentLst.Count)
                {
                    db.CommitTran();
                    apiResponseData.Code = 1;
                    apiResponseData.Data = lst.Count;

                    List<PlanlogInfo> logs = new List<PlanlogInfo>();

                    foreach (KeyValuePair<EnumOperationType, List<DriveMaintencePlanInfo>> item in OperationList)
                    {
                        foreach (DriveMaintencePlanInfo data in item.Value)
                        {
                            DeviceInformationInfo dev = null;
                            if (devs.ContainsKey(data.EquipmentID))
                                dev = devs[data.EquipmentID];
                            else
                                throw new Exception($"没有查询到设备表主键编号为【{data.EquipmentID}】的数据！");

                            logs.Add(new PlanlogInfo
                            {
                                EquipmentAutoID = data.EquipmentID,
                                EquipmentID = dev.EquipmentID,
                                PlanMonth = data.MaintenanceMonth,
                                PlanYear = data.MaintenanceYear,
                                PlanType = data.MaintenanceType,
                                OperationUser = hm.Operator,
                                OperationUserName = hm.OperatorName,
                                OperationComputer = hm.ClientName,
                                OperationIP = hm.IPAddress,
                                OperationDate = CurrentTime,
                                OperationType = EnumOperationType.Add == item.Key ? "新增" : "修改"
                            });
                        }
                    }

                    db.ChangeDatabase("log");
                    db.Insertable(logs).ExecuteCommand();
                }
                else
                {
                    db.RollbackTran();
                    apiResponseData.Code = -1;
                }
            }
            catch (SqlSugarException e)
            {
                db.RollbackTran();
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                db.RollbackTran();
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 获取当前年月的待保修项
        /// </summary>
        /// <returns></returns>
        public APIResponseData GetCurrentMonthPlanTips()
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            try
            {
                db.ChangeDatabase("main");
                base.db.ChangeDatabase("main");

                List<View_CurrentMonthPlanTips> tips = base.db.Queryable<View_CurrentMonthPlanTips>().ToList();
                apiResponseData.Code = 1;
                apiResponseData.Data = tips;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 获取当前年月的待保修项数量
        /// </summary>
        /// <returns></returns>
        public APIResponseData GetCurrentMonthPlanTipsCountAsync()
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            try
            {
                base.db.ChangeDatabase("main");
                int Count = base.db.Queryable<View_CurrentMonthPlanTips>().ToList().Count;

                apiResponseData.Code = 1;
                apiResponseData.Data = Count;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 当前年度计划完成进度
        /// </summary>
        /// <returns></returns>
        public APIResponseData GetCurrentYearPlanSchedule()
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            try
            {
                int CurrentMonth = DateTime.Now.Month;

                base.db.ChangeDatabase("main");
                List<DriveMaintencePlanInfo> Plans = CurrentDb.AsQueryable().Where(x => x.MaintenanceYear == DateTime.Now.Year && SqlFunc.HasValue(x.MaintenanceType)).ToList();

                int[] planIds = Plans.Select(x => x.AutoID).ToArray();
                List<MaintenanceRecordInfo> Records = db.Queryable<MaintenanceRecordInfo>().Where(x => SqlFunc.ContainsArray(planIds, x.PlanPrimaryID)).ToList();

                CurrentYearPlanSchedule schedule = new CurrentYearPlanSchedule();
                schedule.Total = Plans.Count;

                foreach (DriveMaintencePlanInfo item in Plans)
                {
                    MaintenanceRecordInfo Record = Records.Where(x => x.PlanPrimaryID == item.AutoID).FirstOrDefault();

                    if (Record != null)
                    {
                        schedule.Complete++;
                    }
                    else
                    {
                        if (item.MaintenanceMonth == CurrentMonth)
                        {
                            schedule.Current++;
                        }
                        else if (item.MaintenanceMonth > CurrentMonth)
                        {
                            schedule.Future++;
                        }
                        else if (item.MaintenanceMonth < CurrentMonth)
                        {
                            schedule.TimeOut++;
                        }
                    }
                }
                apiResponseData.Code = 1;
                apiResponseData.Data = schedule;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 获取全部计划信息
        /// </summary>
        /// <returns></returns>
        public APIResponseData GetAllPlans()
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            try
            {
                db.ChangeDatabase("main");
                int CurrentMonth = DateTime.Now.Month;

                List<DriveMaintencePlanInfo> Datas = GetList();

                int[] ids = Datas.Select(x => x.EquipmentID).ToArray();
                Dictionary<int, UserInfoModel> usDict = db.Queryable<UserInfoModel>().With(SqlWith.NoLock).ToList().ToDictionary(x => x.AutoID, x => x);
                List<DeviceInformationInfo> devLst = db.Queryable<DeviceInformationInfo>().With(SqlWith.NoLock).Where(x => SqlFunc.ContainsArray(ids, x.AutoID)).ToList();
                int[] formIds = devLst.Select(x => x.MaintenanceFormVersion).ToArray();

                Dictionary<int, DeviceInformationInfo> devDict = devLst.ToDictionary(x => x.AutoID, x => x);

                int[] planIds = Datas.Select(x => x.AutoID).ToArray();
                Dictionary<int, MaintenanceFormVersionInfo> formDict = db.Queryable<MaintenanceFormVersionInfo>().With(SqlWith.NoLock).Where(x => SqlFunc.ContainsArray(formIds, x.AutoID)).ToList().ToDictionary(x => x.AutoID, x => x);
                Dictionary<int, MaintenanceRecordInfo> recordDict = db.Queryable<MaintenanceRecordInfo>().With(SqlWith.NoLock).Where(x => SqlFunc.ContainsArray(planIds, x.PlanPrimaryID)).ToList().ToDictionary(x => x.PlanPrimaryID, x => x);

                List<AnnualMaintenancePlan> lst = new List<AnnualMaintenancePlan>();
                Type type = typeof(AnnualMaintenancePlan);
                foreach (var data in Datas)
                {
                    AnnualMaintenancePlan item = null;
                    if (!lst.Any(x => x.EquipmentID == data.EquipmentID && x.MaintenanceYear == data.MaintenanceYear))
                    {
                        DriveMaintencePlanInfo first = Datas.Where(x => x.EquipmentID == data.EquipmentID && x.MaintenanceYear == data.MaintenanceYear).OrderBy(x => x.CreatDate).FirstOrDefault();
                        DriveMaintencePlanInfo last = Datas.Where(x => x.EquipmentID == data.EquipmentID && x.MaintenanceYear == data.MaintenanceYear).OrderByDescending(x => x.ChangeDate).FirstOrDefault();

                        if (first != null && last != null)
                        {
                            item = new AnnualMaintenancePlan();
                            item.EquipmentID = data.EquipmentID;
                            item.DisplayEquipmentID = devDict[data.EquipmentID].EquipmentID;
                            item.EquipmentName = devDict[data.EquipmentID].EquipmentName;
                            item.VersionCode = formDict.ContainsKey(devDict[data.EquipmentID].MaintenanceFormVersion) ? formDict[devDict[data.EquipmentID].MaintenanceFormVersion].VersionCode : "";
                            item.MaintenanceYear = data.MaintenanceYear;
                            item.PMStartMonth = data.PMStartMonth.ToString("yyyy-MM-dd");
                            item.CreatUser = data.CreatUser;
                            item.CreatUserName = usDict[data.CreatUser].RealName;
                            item.CreatDate = first.CreatDate;
                            item.ChangeDate = null;
                            item.ChangeUser = null;
                            item.ChangeUserName = string.Empty;
                            item.Remarks = data.Remarks;


                            if (last != null && last.ChangeDate.HasValue && last.ChangeUser > 0)
                            {
                                item.ChangeDate = last.ChangeDate;
                                item.ChangeUser = last.ChangeUser;
                                item.ChangeUserName = usDict[last.ChangeUser].RealName;
                                item.Remarks = last.Remarks;
                                item.PMStartMonth = last.PMStartMonth.ToString("yyyy-MM-dd");
                            }

                            lst.Add(item);
                        }
                    }

                    item = lst.FirstOrDefault(x => x.EquipmentID == data.EquipmentID && x.MaintenanceYear == data.MaintenanceYear);

                    if (item != null)
                    {
                        EnumMonth month = (EnumMonth)(data.MaintenanceMonth);
                        PropertyInfo prop = type.GetProperty(month + "");
                        prop.SetValue(item, data.MaintenanceType);

                        EnumPlanCompleteStatus status = EnumPlanCompleteStatus.None;
                        if (string.IsNullOrWhiteSpace(data.MaintenanceType))
                            status = EnumPlanCompleteStatus.None;
                        else if (recordDict.ContainsKey(data.AutoID))
                            status = EnumPlanCompleteStatus.Complete;
                        else
                        {
                            if (data.MaintenanceMonth == CurrentMonth)
                            {
                                status = EnumPlanCompleteStatus.Current;
                            }
                            else if (data.MaintenanceMonth > CurrentMonth)
                            {
                                status = EnumPlanCompleteStatus.Future;
                            }
                            else if (data.MaintenanceMonth < CurrentMonth)
                            {
                                status = EnumPlanCompleteStatus.TimeOut;
                            }
                        }

                        prop = type.GetProperty(month + "Status");
                        prop.SetValue(item, status);
                    }
                }

                apiResponseData.Code = 1;
                apiResponseData.Data = lst.OrderByDescending(x => x.ChangeDate).OrderByDescending(x => x.ChangeDate).ToList();
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 根据设备主键ID取指定年份计划数据
        /// </summary>
        /// <param name="Year"></param>
        /// <param name="EquipmentAutoID"></param>
        /// <returns></returns>
        public APIResponseData GetDataByEquipmentAutoIdOnYear(int Year, int EquipmentAutoID)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            View_AnnualMaintenancePlan Item = null;
            try
            {
                db.ChangeDatabase("main");
                Item = db.Queryable<View_AnnualMaintenancePlan>().First(x => x.MaintenanceYear == Year
                    && x.EquipmentID == EquipmentAutoID);

                apiResponseData.Code = 1;
                apiResponseData.Data = Item;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }


        /// <summary>
        /// 导出EXCEL的数据
        /// </summary>
        /// <returns></returns>
        public APIResponseData ExportXlsxDatas(int Year)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };

            try
            {
                db.ChangeDatabase("main");
                List<View_YearsMaintenancePlansExport> lst = db.Queryable<View_YearsMaintenancePlansExport>().Where(x => x.MaintenanceYear == Year)?.ToList();

                apiResponseData.Code = 1;
                apiResponseData.Data = lst;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 获取当前计划是否存的保养记录
        /// </summary>
        /// <param name="EquipmentID"></param>
        /// <param name="Year"></param>
        /// <returns></returns>
        public APIResponseData GetPlanRecordProgress(int EquipmentID, int Year)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            try
            {
                List<PlanProgress> Datas = db.Queryable<DriveMaintencePlanInfo, MaintenanceRecordInfo>((t1, t2) => new object[] { JoinType.Inner, t1.AutoID == t2.PlanPrimaryID && t1.MaintenanceType == t2.PlanType })
                .Where((t1, t2) => t2.EquipmentPrimaryID == EquipmentID)
                .Select((t1, t2) => new PlanProgress
                {
                    PlanAutoID = t1.AutoID,
                    PlanMonth = t1.MaintenanceMonth,
                    PlanType = t1.MaintenanceType,
                    PlanYear = t1.MaintenanceYear,
                    RecordAutoID = t2.AutoID
                }).ToList();

                apiResponseData.Code = 1;
                apiResponseData.Data = Datas;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 删除计划
        /// </summary>
        /// <param name="Year"></param>
        /// <param name="EquipmentAutoID"></param>
        /// <returns></returns>
        public APIResponseData DeleteByYearAndEquipmentPk(int Year, int EquipmentAutoID)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"操作失败！" };
            try
            {
                db.ChangeDatabase("main");
                bool isSuccess = CurrentDb.Delete(x => x.MaintenanceYear == Year && x.EquipmentID == EquipmentAutoID);
                if (isSuccess)
                    return new APIResponseData { Code = 1 };
                else
                    return apiResponseData;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }

        /// <summary>
        /// 获取设备在年度的全部保养信息
        /// </summary>
        /// <param name="EquipmentAutoID"></param>
        /// <param name="Year"></param>
        /// <returns></returns>
        public APIResponseData GetDeviceInformationPlans(int EquipmentAutoID, int Year)
        {
            APIResponseData apiResponseData = new APIResponseData { Code = -1, Message = $"获取数据失败！" };
            if (EquipmentAutoID <= 0 || Year <= 0)
                return new APIResponseData { Code = -1, Message = "传入的设备编号或年份参数出错！" };
            try
            {
                db.ChangeDatabase("main");

                // 获取设备计划信息
                DeviceInformationInfo Dev = db.Queryable<DeviceInformationInfo>().First(x => x.AutoID == EquipmentAutoID);

                if (Dev == null)
                    throw new Exception($"编号为：{EquipmentAutoID} 的设备不存在！");

                // 获取计划信息
                List<DriveMaintencePlanInfo> plans = db.Queryable<DriveMaintencePlanInfo>().Where(x => x.EquipmentID == EquipmentAutoID && x.MaintenanceYear == Year && SqlFunc.HasValue(x.MaintenanceType)).ToList();
                if ((plans?.Count ?? 0) == 0)
                    throw new Exception($"编号为：{EquipmentAutoID} 的设备计划为空！");

                int[] pIds = plans.Select(x => x.AutoID).ToArray();

                // 获取保养的记录信息
                List<MaintenanceRecordInfo> records = db.Queryable<MaintenanceRecordInfo>().Where(x => x.EquipmentPrimaryID == EquipmentAutoID && SqlFunc.ContainsArray(pIds, x.PlanPrimaryID)).ToList();

                DeviceAnnPlanView devs = new DeviceAnnPlanView
                {
                    Dev = Dev,
                    Plans = plans,
                    Records = records
                };

                if (Dev.MaintenanceFormVersion != 0)
                    devs.CurrentFormCode = db.Queryable<MaintenanceFormVersionInfo>().First(x => x.AutoID == Dev.MaintenanceFormVersion)?.VersionCode;

                apiResponseData.Code = 1;
                apiResponseData.Message = "";
                apiResponseData.Data = devs;
            }
            catch (SqlSugarException e)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = e.Message;
            }
            catch (Exception ex)
            {
                apiResponseData.Code = -1;
                apiResponseData.Message = ex.Message;
            }
            return apiResponseData;
        }
    }
}
