using System;
using System.Collections.Generic;
using System.Linq;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.AccRepository;
using Siger.Middlelayer.CncRepository;
using Siger.Middlelayer.DashboardRepository;
using Siger.Middlelayer.CncRepository.Response;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.FieldEnum;
using Siger.Middlelayer.Common.Log;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Dapper;
using Siger.Middlelayer.Dapper.SearchCondition;
using Siger.Middlelayer.Dapper.Utilities.Slice;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.AccRepository.Entities;
using Siger.Middlelayer.DashboardRepository.Response;

namespace Siger.ApiDashboard.Tasks.Reports
{
    internal class ReportDbHelper
    {
        private static ReportDbHelper _helper;
        public static ReportDbHelper Instance = _helper ?? (_helper = new ReportDbHelper());

        public ApiCncDbContext CncDbContext;
        public ApiAccDbContext AccDbContext;
        public ApiConfigDbContext ConfigDbContext;

        static ReportDbHelper()
        {
        }
        public void LoadDbContext()
        {
            CncDbContext = new ApiCncDbContext();
            AccDbContext = new ApiAccDbContext();
            ConfigDbContext = new ApiConfigDbContext();
        }
        public void Dispose()
        {
            CncDbContext.Dispose();
            AccDbContext.Dispose();
            ConfigDbContext.Dispose();
        }

        public IList<siger_project_monthreport_config> GetAllConfigs()
        {
            var configList = new List<siger_project_monthreport_config>();
            var configs = CncDbContext.siger_project_monthreport_config.Where(q => q.status == (int)RowState.Valid
                                                                               && q.first_date <= DateTime.Now && q.user_mids != "").ToList();
            //过滤发送时间
            foreach (var config in configs)
            {

                if (config.day_interval == "3")
                {
                    var monthDay = config.send_time.ToDateTime();
                    if (DateTime.Now.Day != monthDay.Day)
                        continue;

                    if (DateTime.TryParse($"{DateTime.Now.ToShortDateString()}{" "}{config.send_time.Replace($"{DateTime.Now.ToString(ParameterConstant.DateFormat)} ", "")}", out DateTime dts))
                    {
                        var seconds = DateTime.Now.Subtract(dts).TotalSeconds;
                        if (seconds >= 0 && seconds < 300)
                        {
                            configList.Add(config);
                        }
                    }
                }
                else
                {
                    if (DateTime.TryParse(DateTime.Now.ToShortDateString() + " " + config.send_time, out DateTime dt))
                    {
                        var seconds = DateTime.Now.Subtract(dt).TotalSeconds;
                        if (seconds >= 0 && seconds < 300)
                        {
                            var needSend = IsNeedSendReport(config);
                            if (needSend)
                            {
                                configList.Add(config);
                            }
                        }
                    }
                }



            }
            return configList;
        }
        public IList<siger_project_monthreport_config> GetConfigs()
        {
            return CncDbContext.siger_project_monthreport_config.Where(q => q.status == (int)RowState.Valid
                                                                             && q.first_date <= DateTime.Now && q.user_mids != "").ToList();
        }

        public IEnumerable<siger_project_monthreport_config_template> GetRptTemplates(int typeId)
        {
            return ConfigDbContext.siger_project_monthreport_config_template.Where(f => f.parent_id == typeId);
        }
        private bool IsNeedSendReport(siger_project_monthreport_config config)
        {
            if (config.cycle == MonthReportCycle.Day)
            {
                var dtStart = config.first_date.Date;
                var dtEnd = config.first_date.AddYears(1); //默认查一年的
                DateTime dtDay;
                var interval = config.day_interval.ToInt();
                for (dtDay = dtStart; dtDay.CompareTo(dtEnd) <= 0; dtDay = dtDay.AddDays(interval).Date)
                {
                    if (dtDay.Date.Subtract(DateTime.Now.Date).TotalDays == 0)
                    {
                        return true;
                    }
                }
            }

            if (config.cycle == MonthReportCycle.Week)
            {
                if (!string.IsNullOrWhiteSpace(config.day_interval))
                {
                    var days = config.day_interval.Split(',').ToList();
                    var now = DateTime.Now.DayOfWeek;
                    foreach (var day in days)
                    {
                        if (day.ToInt() == (int)now)
                        {
                            return true;
                        }
                    }
                }
            }

            if (config.cycle == MonthReportCycle.Month)
            {
                if (config.day_interval == "1") //月初
                {
                    if (DateTime.Now.Day == 1)
                    {
                        return true;
                    }
                }
                else if (config.day_interval == "2") //月末
                {
                    if (DateTime.Today.AddDays(1) == DateTime.Parse(DateTime.Now.AddMonths(1).ToString("yyyy-MM-01")))
                    {
                        return true;
                    }
                }

            }

            return false;
        }

        public IEnumerable<int> GetMachineIds(siger_project_monthreport_config config)
        {
            if (string.IsNullOrWhiteSpace(config.sectionids))
            {
                return new List<int>();
            }

            var sectionIds = config.sectionids.Split(',').ToList();
            var machineIds = CncDbContext.siger_project_level_section_machine.Where(q =>
                    sectionIds.Contains(q.section_id.ToString()) && q.status == (int)RowState.Valid)
                .Select(m => m.machine_id)
                .Distinct()
                .ToList();

            var validMachines =
                CncDbContext.siger_project_machine.Where(q => machineIds.Contains(q.id) && q.projectid == config.project_id && q.status == (int)RowState.Valid && q.category == (int)MachineCategory.NC);

            return validMachines.Select(m => m.id).Distinct().ToList();
        }
        /// <summary>
        ///  获取组别下的设备ID
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public IEnumerable<int> GetMachineIdsByGroup(int projectId, string groupMids)
        {
            if (string.IsNullOrEmpty(groupMids))
                return new List<int>();

            var ids = groupMids.Split(',').Select(t => t.ToInt()).ToList();
            var mids = CncDbContext.siger_project_machine.Where(q => ids.Contains(q.id) && q.projectid == projectId && q.status == (int)RowState.Valid).Select(s => s.id).Distinct().ToList();
            return mids;
        }
        public IEnumerable<int> GetMachineIds(siger_project_monthreport_config_template template)
        {
            if (string.IsNullOrWhiteSpace(template.param))
                return new List<int>();

            var sectionIds = template.param.Split(',').Select(t => t.ToInt());
            if (template.tab == 2)
            {
                var grpMachineIds = ConfigDbContext.siger_project_dashboard_machine_group.Where(f => f.projectid == template.project_id && sectionIds.Contains(f.id)).Select(m => m.machineid).Distinct();

                var machines = new List<int>();
                foreach (var g in grpMachineIds)
                {
                    var ids = g.Split(',').Select(t => t.ToInt()).ToList();
                    var mids = CncDbContext.siger_project_machine.Where(q => ids.Contains(q.id) && q.projectid == template.project_id && q.status == (int)RowState.Valid).Select(s => s.id).Distinct().ToList();
                    machines.AddRange(mids);
                }
                return machines.Distinct();
            }

            //var machineIds = CncDbContext.siger_project_level_section_machine.Where(q =>
            //        sectionIds.Contains(q.section_id) && q.status == (int)RowState.Valid)
            //    .Select(m => m.machine_id)
            //    .Distinct()
            //    .ToList();
            var machineIds = CncDbContext.siger_project_machine_attribution.Where(q =>
                   sectionIds.Contains(q.station) && q.status == (int)RowState.Valid)
               .Select(m => m.machine).Distinct().ToList();
            var validMachines =
                CncDbContext.siger_project_machine.Where(q => machineIds.Contains(q.id) && q.projectid == template.project_id && q.status == (int)RowState.Valid && q.category == (int)MachineCategory.NC);
            return validMachines.Select(m => m.id).Distinct().ToList();
        }

        public int ProjectLanguage(int projectId)
        {
            var project = AccDbContext.siger_project.FirstOrDefault(t => t.id == projectId && t.status == (int)RowState.Valid);
            return project?.language ?? 0;
        }

        public string GetTimeRange(siger_project_monthreport_config config)
        {
            var range = TimeRange(config);
            return range.StartTime + " - " + range.EndTime;
        }
        public string GetProductCode(siger_project_monthreport_config config)
        {
            var productCode = string.Empty;
            var product = AccDbContext.siger_project_product.Where(s => s.id == config.product_id).FirstOrDefault();
            if (product != null)
            {
                productCode = product.code;
            }
            return productCode;
        }

        public TimeRange TimeRange(siger_project_monthreport_config config)
        {
            var dtStrat = string.Empty;
            var dtEnd = string.Empty;
            if (config.cycle == MonthReportCycle.Day)
            {
                dtStrat = DateTime.Parse(DateTime.Now.AddDays(-config.day_interval.ToInt()).ToString(ParameterConstant.DateFormat) + " " + config.send_time).ToString(ParameterConstant.DateTimeFormat);

                dtEnd = DateTime.Parse(DateTime.Now.ToString(ParameterConstant.DateFormat) + " " + config.send_time).ToString(ParameterConstant.DateTimeFormat);
            }

            if (config.cycle == MonthReportCycle.Week)
            {
                int interval = 7;
                var days = config.day_interval.Split(',');
                if (days.Length > 1)
                {
                    var dayofweek = DateTime.Now.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)DateTime.Now.DayOfWeek;
                    var listDays = new List<int>();
                    foreach (var day in days)
                    {
                        listDays.Add(day == "0" ? 7 : day.ToInt());
                    }

                    for (var i = 0; i < listDays.Count; i++) //从1到7
                    {
                        var day = listDays[i];
                        if (day == dayofweek)
                        {
                            if (i == 0)
                            {
                                interval = 7 - (listDays[listDays.Count - 1] - dayofweek);
                            }
                            else
                            {
                                interval = listDays[listDays.Count - 1] - listDays[i - 1];
                            }
                        }
                    }
                }

                dtStrat = DateTime.Parse(DateTime.Now.AddDays(-interval).ToString(ParameterConstant.DateFormat) + " " + config.send_time).ToString(ParameterConstant.DateTimeFormat);
                dtEnd = DateTime.Parse(DateTime.Now.ToString(ParameterConstant.DateFormat) + " " + config.send_time).ToString(ParameterConstant.DateTimeFormat);
            }

            if (config.cycle == MonthReportCycle.Month)
            {
                if (config.day_interval == "1")
                {
                    dtStrat = DateTime.Now.AddMonths(-1).ToString(ParameterConstant.MouthFirstDay + ParameterConstant.TimeFromZero);
                    dtEnd = DateTime.Now.AddDays(-1).ToString(ParameterConstant.DateToEnd);

                    return new TimeRange(dtStrat.ToDateTime(), dtEnd.ToDateTime());
                }
                else if (config.day_interval == "3")
                {
                    dtStrat = DateTime.Now.AddMonths(-1).ToString(ParameterConstant.MouthFirstDay + ParameterConstant.TimeFromZero);
                    dtEnd = DateTime.Now.AddDays(1 - DateTime.Now.Day).AddDays(-1).ToString(ParameterConstant.DateToEnd);
                }
                else
                {
                    dtStrat = DateTime.Parse(DateTime.Now.ToString(ParameterConstant.MouthFirstDay) + " " + config.send_time)
                        .ToString(ParameterConstant.DateTimeFormat);
                    dtEnd = DateTime.Parse(DateTime.Now.AddMonths(1).ToString(ParameterConstant.MouthFirstDay) + " " + config.send_time)
                        .AddSeconds(-1)
                        .ToString(ParameterConstant.DateTimeFormat);
                }
            }

            return new TimeRange(dtStrat.ToDateTime(), dtEnd.ToDateTime());
        }

        public SigerProjectEmailConfig GetEmailConfigs(int projectId)
        {
            return CncDbContext.siger_project_email_config.FirstOrDefault(q => q.project == projectId && q.status == (int)RowState.Valid);
        }

        public IEnumerable<siger_project_user> UserEmails(string userMids)
        {
            var userIds = userMids.Split(',').ToList();

            return CncDbContext.siger_project_user.Where(q =>
                userIds.Contains(q.mid.ToString()) && q.work_email != "" && q.status == (int)RowState.Valid).ToList();
        }

        public void AddSendRecord(int configId, string acceptUsers, string filePath)
        {
            try
            {
                var entity = new siger_project_monthreport_sendrecord
                {
                    config_id = configId,
                    send_time = DateTime.Now,
                    accept_mid = 0,
                    accept_usernames = acceptUsers,
                    file_path = filePath ?? "",
                    file_content = new byte[] { },
                    status = (int)RowState.Valid
                };
                CncDbContext.siger_project_monthreport_sendrecord.Add(entity);
                CncDbContext.SaveChanges();
            }
            catch (Exception e)
            {
                Logger.WriteLineError(e.ToString());
            }
        }

        public IEnumerable<MachineData> GetLevelSectionNames(IEnumerable<int> machineIds, int projectid)
        {
            var querylist = from q in CncDbContext.siger_project_level_section_machine
                            join m in CncDbContext.siger_project_machine on q.machine_id equals m.id
                            join se in CncDbContext.siger_project_level_section on q.section_id equals se.id
                            join se2 in CncDbContext.siger_project_level_section on se.parentid equals se2.id
                            where machineIds.Contains(q.machine_id) && q.status == (int)RowState.Valid &&
                                  m.status == (int)RowState.Valid && se.status == (int)RowState.Valid
                                  && m.projectid == projectid && m.category == (int)MachineCategory.NC
                            select new MachineData
                            {
                                machine_id = m.id,
                                machine_name = m.title,
                                machine_code = m.code,
                                section_id = se.id,
                                lastSectionTitle = se.title,
                                lastSecondSectionTitle = se2.title
                            };

            return querylist.ToList();
        }

        public IEnumerable<MachineData> GetMachineLocation(IEnumerable<int> machineIds)
        {
            //from q in CncDbContext.siger_project_level_section_machine
            var querylist = from q in CncDbContext.siger_project_machine_attribution
                            join m in CncDbContext.siger_project_machine on q.machine equals m.id
                            join se in CncDbContext.siger_project_level_section on q.station equals se.id
                            join se2 in CncDbContext.siger_project_level_section on se.parentid equals se2.id
                            where machineIds.Contains(q.machine) && q.status == (int)RowState.Valid &&
                                  m.status == (int)RowState.Valid && se.status == (int)RowState.Valid && m.category == (int)MachineCategory.NC
                            select new MachineData
                            {
                                machine_id = m.id,
                                machine_name = m.title,
                                machine_code = m.code,
                                section_id = se.id,
                                lastSectionTitle = se.title,
                                lastSecondSectionTitle = se2.title
                            };

            return querylist.ToList();
        }

        //设备报警
        public GetAlarmDataForMoutReport GetAlarmDataForAnalysis(IEnumerable<int> machineIds, int companyId, int projectId, DateTime now)
        {
            var dtStart = now.AddDays(-14).ToShortDateString();
            var dtEnd = now.ToString(ParameterConstant.DateTimeFormat);

            var condition = new CncAlarmAnalysResultCondition
            {
                STime = dtStart,
                ETime = dtEnd,
            };

            var cncExceptionRepository = new AlarmAnalysResultRepository(companyId, projectId);
            var exceptions = cncExceptionRepository.GetNoPagedCncExceptionParamsSates(condition);

            var response = new GetAlarmDataForMoutReport();

            for (var i = 14; i >= 0; i--)
            {
                var start = now.AddDays(-i);
                var end = start.AddDays(1).AddSeconds(-1);
                response.xdata.Add(start.ToString(ParameterConstant.MonthDayFormay));

                double totalSeconds = (int)exceptions.Where(q => q.Stime >= start && q.Stime <= end).Sum(q => (q.Etime - q.Stime).TotalSeconds);
                response.ydata.Add(Math.Round(totalSeconds / 3600, 1));
            }

            var machines = CncDbContext.siger_project_machine.Where(q =>
                machineIds.Contains(q.id) && q.projectid == projectId && q.status == (int)RowState.Valid && q.category == (int)MachineCategory.NC).ToList();

            var summary = new List<ResponseGetAlarmDataForMoutReport>();
            foreach (var machineId in machineIds)
            {
                var machine = machines.FirstOrDefault(q => q.id == machineId);
                if (machine != null)
                {
                    var machineExceptions = exceptions.Where(m => m.machineId == machineId);
                    double totalAlarm = 0;
                    foreach (var exception in machineExceptions)
                    {
                        totalAlarm += exception.Etime.Subtract(exception.Stime).TotalSeconds / 3600;
                    }

                    summary.Add(new ResponseGetAlarmDataForMoutReport
                    {
                        Abscissa = machine.title,
                        duration = Math.Round(totalAlarm, 1),
                        times = machineExceptions.Count()
                    });
                }
            }

            foreach (var mach in summary.OrderByDescending(q => q.duration).Take(5))
            {
                response.topduration.Add(mach);
            }

            foreach (var mach in summary.OrderByDescending(q => q.times).Take(5))
            {
                response.toptimes.Add(mach);
            }

            return response;
        }

        //当天设备运行情况
        //public MachineStatusSummary GetStatusSummary(IEnumerable<int> machineIds, int companyId, int projectId, DateTime now)
        //{
        //    var result = new MachineStatusSummary();
        //    var machineCount = machineIds.Count();
        //    if (machineCount == 0)
        //    {
        //        return result;
        //    }

        //    var repositoey = new SliceSateRepository(companyId, projectId);
        //    var dtStart = now.AddDays(-1).ToShortDateString();
        //    var dtEnd = now.ToString(ParameterConstant.DateTimeFormat);
        //    var daySliceSates = repositoey.GetCncSliceSates(machineIds, dtStart, dtEnd);

        //    var totalTimes = 86400 * machineCount;
        //    var dayStatus = SliceManager.GetMachineStatusHold(machineIds, DateTime.Parse(dtStart), DateTime.Parse(dtEnd), daySliceSates);
        //    if (dayStatus != null)
        //    {
        //        result.runtotal = Math.Round(dayStatus.First(q => q.Status == MachineRunningStatus.Running).TimeSpan / 3600, 1);
        //        result.faulttotal = Math.Round(dayStatus.First(q => q.Status == MachineRunningStatus.Fault).TimeSpan / 3600, 1);
        //        result.idletotal = Math.Round(dayStatus.First(q => q.Status == MachineRunningStatus.Free).TimeSpan / 3600, 1);
        //        result.debugtotal = Math.Round(dayStatus.First(q => q.Status == MachineRunningStatus.Debugging).TimeSpan / 3600, 1);
        //        result.shutdowntotal = Math.Round(dayStatus.First(q => q.Status == MachineRunningStatus.Shutdown).TimeSpan / 3600, 1);

        //        result.runaverage = Math.Round(result.runtotal / machineCount, 1);
        //        result.faultaverage = Math.Round(result.faulttotal / machineCount, 1);
        //        result.idleaverage = Math.Round(result.idletotal / machineCount, 1);
        //        result.debugaverage = Math.Round(result.debugtotal / machineCount, 1);
        //        result.shutdownaverage = Math.Round(result.shutdowntotal / machineCount, 1);

        //        result.runpercent = Math.Round(result.runtotal / totalTimes * 100, 1);
        //        result.faultpercent = Math.Round(result.faulttotal / totalTimes * 100, 1);
        //        result.idlepercent = Math.Round(result.idletotal / totalTimes * 100, 1);
        //        result.debugpercent = Math.Round(result.debugtotal / totalTimes * 100, 1);
        //        result.shutdownpercent = Math.Round(result.shutdowntotal / totalTimes * 100, 1);
        //    }

        //    var dic = new Dictionary<int, double>();
        //    //运行top5
        //    foreach (var machineId in machineIds)
        //    {
        //        var machineSates = daySliceSates.Where(q => q.MachineID == machineId);

        //        var run = SliceManager.GetRunTime(DateTime.Parse(dtStart), DateTime.Parse(dtEnd), machineSates, new List<int> { machineId });

        //        dic.Add(machineId, Math.Round(run / 3600));
        //    }

        //    var machines = CncDbContext.siger_project_machine.Where(q =>
        //        machineIds.Contains(q.id) && q.projectid == projectId && q.status == (int)RowState.Valid && q.category == (int)MachineCategory.NC).ToList();

        //    foreach (var mach in dic.OrderByDescending(q => q.Value).Take(5))
        //    {
        //        var machine = machines.FirstOrDefault(q => q.id == mach.Key);
        //        if (machine != null)
        //        {
        //            result.topgood.Add(new StatusSummary
        //            {
        //                name = machine.title,
        //                run = mach.Value
        //            });
        //        }
        //    }

        //    foreach (var mach in dic.OrderBy(q => q.Value).Take(5))
        //    {
        //        var machine = machines.FirstOrDefault(q => q.id == mach.Key);
        //        if (machine != null)
        //        {
        //            result.topbad.Add(new StatusSummary
        //            {
        //                name = machine.title,
        //                run = mach.Value
        //            });
        //        }
        //    }

        //    return result;
        //}

        public IEnumerable<MachineRestInfo> GetRestTimesByMachine(IEnumerable<int> machineIds, int projectId)
        {
            var result = new List<MachineRestInfo>();
            foreach (var machineId in machineIds)
            {
                var times = CncDbContext.siger_project_production_time.Where(m =>
                    m.machineid == machineId && m.status == (int)RowState.Valid && m.projectid == projectId).ToList();
                foreach (var time in times)
                {
                    result.Add(new MachineRestInfo
                    {
                        BingTime = time.bing_time,
                        EndTime = time.end_time,
                        MachineId = machineId,
                        SectionId = time.sectionid,
                        TimeType = (TimeType)time.typeid
                    });
                }
            }

            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="template"></param>
        /// <returns></returns>
        public string LineTitle(siger_project_monthreport_config_template template)
        {
            var sectionIds = template.param.Split(',').Select(t => t.ToInt());
            var query = from l in ConfigDbContext.siger_project_level_section
                        join ls in ConfigDbContext.siger_project_level_section on l.parentid equals ls.id
                        where sectionIds.Contains(l.id)
                        select ls;

            var r = query.FirstOrDefault();
            if (r != null)
                return r.title;
            else
                return "";
        }
        /// <summary>
        /// 追溯数据
        /// </summary>
        /// <param name="sectionIds">machineIds</param>
        /// <param name="projectId"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public IEnumerable<ResponseMonthReportTrace> GetTraceInfo(List<int> sectionIds, int projectId, DateTime begin, DateTime end)
        {
            var query = from q in AccDbContext.siger_tr_sn_trace
                        join l in AccDbContext.siger_project_level_section on q.Station equals l.id
                        join ls in AccDbContext.siger_project_level_section on l.parentid equals ls.id

                        where q.projectId == projectId && q.TransDateTime >= begin && q.TransDateTime <= end && sectionIds.Contains(q.Station)
                        select new ResponseMonthReportTrace
                        {
                            Id = q.id,
                            Sn = q.SN,
                            Station = l.title,
                            Line = ls.title,
                            Result = q.Result,
                            Transdate = q.TransDateTime
                        };
            return query;
        }
    }
}
