using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Dapper.ResultData;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.Share.Models.Cnc;

namespace Siger.Middlelayer.Dapper.Utilities.Slice
{
    public class SliceManager
    {
        public static IList<MachineStatusTime> GetMachineStatusHold(IEnumerable<int> machineIds, DateTime dtStart, DateTime dtEnd, IEnumerable<CncSliceSate> sliceSates)
        {
            var result = new List<MachineStatusTime>();
            double shutdown = 0; //关机
            double running = 0; //运行
            double debugging = 0; //调试
            double free = 0; //空闲
            double fault = 0; //故障
            var source = sliceSates.Where(q => machineIds.Contains(q.MachineID)
                                               && ((q.StartTime >= dtStart && q.EndTime <= dtEnd)
                                               || (q.StartTime < dtStart && q.EndTime > dtStart && q.EndTime <= dtEnd)
                                               || (q.StartTime >= dtStart && q.StartTime < dtEnd && q.EndTime > dtEnd)
                                               || (q.StartTime < dtStart && q.EndTime > dtEnd))).ToList();
            if (!source.Any())
            {
                return null;
            }

            foreach (var sate in source)
            {
                var data = new MachineStatusHold
                {
                    machine_status = sate.Status,
                    start_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.StartTime),
                    end_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.EndTime)
                };
                if (sate.StartTime < dtStart)
                {
                    data.start_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtStart);
                }
                if (sate.EndTime > dtEnd)
                {
                    data.end_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtEnd);
                }

                data.time_span = data.end_time - data.start_time;
                Increase(sate.Status, data.time_span, ref shutdown, ref running, ref debugging, ref free, ref fault);
            }

            result.Add(new MachineStatusTime { Status = MachineRunningStatus.Shutdown, TimeSpan = shutdown });
            result.Add(new MachineStatusTime { Status = MachineRunningStatus.Running, TimeSpan = running });
            result.Add(new MachineStatusTime { Status = MachineRunningStatus.Debugging, TimeSpan = debugging });
            result.Add(new MachineStatusTime { Status = MachineRunningStatus.Free, TimeSpan = free });
            result.Add(new MachineStatusTime { Status = MachineRunningStatus.Fault, TimeSpan = fault });

            return result;
        }

        public static void Increase(int status, double value, ref double shutdown, ref double running, ref double debugging, ref double free, ref double fault)
        {
            if (value <= 0)
            {
                return;
            }
            switch (status)
            {
                case (int)MachineRunningStatus.Shutdown:
                    shutdown += value;
                    break;
                case (int)MachineRunningStatus.Running:
                    running += value;
                    break;
                case (int)MachineRunningStatus.Debugging:
                    debugging += value;
                    break;
                case (int)MachineRunningStatus.Free:
                    free += value;
                    break;
                case (int)MachineRunningStatus.Fault:
                    fault += value;
                    break;
            }
        }

        public static double GetRunTime(DateTime dtStart, DateTime dtEnd, IEnumerable<CncSliceSate> sliceSates, IEnumerable<int> machineIds)
        {
            double run = 0;
            if (dtEnd > DateTime.Now)
            {
                dtEnd = DateTime.Now;
            }

            var holdTimes = GetMachineStatusHold(machineIds, dtStart, dtEnd, sliceSates);
            if (holdTimes != null && holdTimes.Any())
            {
                foreach (var shutdownHoldTime in holdTimes)
                {
                    if (shutdownHoldTime.Status == MachineRunningStatus.Running)
                    {
                        run += shutdownHoldTime.TimeSpan;
                    }
                }
            }

            return run;
        }

        public static double GetResetTimesBySlice(int status, IEnumerable<TimeRange> programTimes, IEnumerable<CncSliceSate> sliceSates, IEnumerable<RestTimeInfo> times)
        {
            double total = 0;
            double totalSub = 0;
            foreach (var timeRange in programTimes)
            {
                var sates = sliceSates.Where(q => q.Status == status && ((q.StartTime >= timeRange.StartTime && q.EndTime <= timeRange.EndTime)
                                                   || (q.StartTime < timeRange.StartTime && q.EndTime > timeRange.StartTime && q.EndTime <= timeRange.EndTime)
                                                   || (q.StartTime >= timeRange.StartTime && q.StartTime < timeRange.EndTime && q.EndTime > timeRange.EndTime)
                                                   || (q.StartTime < timeRange.StartTime && q.EndTime > timeRange.EndTime))).ToList();
                foreach (var sate in sates)
                {
                    DateTime start = sate.StartTime;
                    DateTime end = sate.EndTime;
                    if (timeRange.StartTime >= start && timeRange.StartTime <= end)
                    {
                        start = timeRange.StartTime;
                    }
                    if (timeRange.EndTime >= start && timeRange.EndTime <= end)
                    {
                        end = timeRange.EndTime;
                    }

                    total += end.Subtract(start).TotalSeconds;
                    if (times != null)
                    {
                        foreach (var restTime in times)
                        {
                            double sub = 0;
                            if (restTime.StartTime >= start && restTime.EndTime > end && restTime.StartTime <= end)
                            {
                                sub = end.Subtract(restTime.StartTime).TotalSeconds;
                            }
                            else if (restTime.StartTime >= start && restTime.EndTime <= end)
                            {
                                sub = restTime.EndTime.Subtract(restTime.StartTime).TotalSeconds;
                            }
                            else if (restTime.StartTime <= start && restTime.EndTime >= end)
                            {
                                sub = end.Subtract(start).TotalSeconds;
                            }
                            else if (restTime.EndTime >= start && restTime.EndTime <= end && restTime.StartTime < start)
                            {
                                sub = end.Subtract(start).TotalSeconds;
                            }

                            totalSub += sub;
                        }
                    }
                }
            }

            return total - totalSub;
        }

        public static async Task<MachineCanvasParetoInfoResult> GetMachineSliceNew(DateTime dtStart, DateTime dtEnd,
            IEnumerable<int> machineIds, IEnumerable<MachineData> machines, int companyId, int projectId)
        {
            var result = new MachineCanvasParetoInfoResult
            {
                startTime = dtStart.ToString(ParameterConstant.DateTimeFormat),
                endTime = dtEnd.ToString(ParameterConstant.DateTimeFormat),
                total_time_span = (dtEnd - dtStart).TotalSeconds
            };

            var repository = new SliceSateRepository(companyId, projectId);

            var sliceSates = await repository.GetCncSliceSatesAsync(machineIds, dtStart.ToString(ParameterConstant.DateTimeFormat), dtEnd.ToString(ParameterConstant.DateTimeFormat));
            if (sliceSates == null || !sliceSates.Any())
            {
                return result;
            }

            var cncSliceSates = sliceSates.ToList();
            foreach (var machineId in machineIds)
            {
                var source = cncSliceSates.Where(q => q.MachineID == machineId).ToList();
                if (!source.Any())
                {
                    continue;
                }
                var machine = machines.FirstOrDefault(q => q.machine_id == machineId);
                ///var machineTitle = machine != null ? machine.lastSecondSectionTitle + "-" + machine.lastSectionTitle : "";
                var machineTitle = machine != null ?  machine.lastSectionTitle : "";

                double shutdown = 0; //关机
                double running = 0; //运行
                double debugging = 0; //调试
                double free = 0; //空闲
                double fault = 0; //故障
                double changeDebugging = 0;

                var canvas = new Canvas
                {
                    machineID = machineId,
                    t_start_time = dtStart.ToString(ParameterConstant.DateFormat) + "T" + dtStart.ToString(ParameterConstant.TimeFormat),
                    t_end_time = dtEnd.ToString(ParameterConstant.DateFormat) + "T" + dtEnd.ToString(ParameterConstant.TimeFormat),
                    machineTitle = machineTitle,
                };

                foreach (var sate in source)
                {
                    var data = new MachineStatusHold
                    {
                        machine_status = sate.Status,
                        workModeId = sate.WordingModeId,
                        workMode = sate.WordingName,
                        remark = sate.Remark,
                        userName = sate.UserName,
                        start_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.StartTime),
                        end_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.EndTime)
                    };
                    if (sate.StartTime < dtStart)
                    {
                        data.start_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtStart);
                    }
                    if (sate.EndTime > dtEnd)
                    {
                        data.end_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtEnd);
                    }

                    data.time_span = data.end_time - data.start_time;
                    Increase(sate.Status, data.time_span, ref shutdown, ref running, ref debugging, ref free, ref fault, ref changeDebugging);
                    canvas.list_msh.Add(data);
                }

                var maxTime = canvas.list_msh.Max(q => q.end_time);
                var minTime = UnixTimeHelper.ConvertDataTimeLong(dtStart);
                canvas.t_time_Span = maxTime - minTime;
                result.canvas.Add(canvas);

                var paretoData = new Pareto
                {
                    machineID = machineId,
                    machineTitle = machineTitle,
                    total = result.total_time_span,
                };
                paretoData.listShutdownHoldTime.Add(new ShutdownHoldTime
                {
                    factor = "shutdown",
                    timeSpan = shutdown,
                    factorName = "关机"
                });
                paretoData.listShutdownHoldTime.Add(new ShutdownHoldTime
                {
                    factor = "running",
                    timeSpan = running,
                    factorName = "运行"
                });
                paretoData.listShutdownHoldTime.Add(new ShutdownHoldTime
                {
                    factor = "debugging",
                    timeSpan = debugging,
                    factorName = "手动/调试"
                });
                paretoData.listShutdownHoldTime.Add(new ShutdownHoldTime
                {
                    factor = "free",
                    timeSpan = free,
                    factorName = "空闲"
                });
                paretoData.listShutdownHoldTime.Add(new ShutdownHoldTime
                {
                    factor = "fault",
                    timeSpan = fault,
                    factorName = "报警"
                });
                result.pareto.Add(paretoData);
            }

            return result;
        }

        public static async Task<MachineCanvas> GetMachineSlice(DateTime dtStart, DateTime dtEnd,
            IEnumerable<int> machineIds, IEnumerable<MachineData> machines, int companyId, int projectId)
        {
            var result = new MachineCanvas();
            var repository = new SliceSateRepository(companyId, projectId);

            var sliceSates = await repository.GetCncSliceSatesAsync(machineIds, dtStart.ToString(ParameterConstant.DateTimeFormat), dtEnd.ToString(ParameterConstant.DateTimeFormat));
            if (sliceSates == null || !sliceSates.Any())
            {
                return result;
            }

            return await Task.Run(() =>
            {
                var tStartTime = dtStart.ToString(ParameterConstant.DateFormat) + "T" + dtStart.ToString(ParameterConstant.TimeFormat);
                var tEndTime = dtEnd.ToString(ParameterConstant.DateFormat) + "T" + dtEnd.ToString(ParameterConstant.TimeFormat);

                var cncSliceSates = sliceSates.ToList();
                foreach (var machineId in machineIds)
                {
                    var machine = machines.FirstOrDefault(q => q.machine_id == machineId);
                    if (machine == null)
                    {
                        continue;
                    }

                    var source = cncSliceSates.Where(q => q.MachineID == machineId).ToList();
                    if (!source.Any())
                    {
                        continue;
                    }

                    double shutdown = 0; //关机
                    double running = 0; //运行
                    double debugging = 0; //调试
                    double free = 0; //空闲
                    double fault = 0; //故障
                    double changeDebugging = 0;

                    var canvas = new Canvas
                    {
                        machineID = machineId,
                        machineTitle = machine.lastSecondSectionTitle + "-" + machine.lastSectionTitle,
                        t_start_time = tStartTime,
                        t_end_time = tEndTime,
                    };

                    foreach (var sate in source)
                    {
                        var data = new MachineStatusHold
                        {
                            machine_status = sate.Status,
                            workModeId = sate.WordingModeId,
                            workMode = sate.WordingName,
                            remark = sate.Remark,
                            userName = sate.UserName,
                            start_time = (int) UnixTimeHelper.ConvertDataTimeLong(sate.StartTime),
                            end_time = (int) UnixTimeHelper.ConvertDataTimeLong(sate.EndTime)
                        };
                        if (sate.StartTime < dtStart)
                        {
                            data.start_time = (int) UnixTimeHelper.ConvertDataTimeLong(dtStart);
                        }

                        if (sate.EndTime > dtEnd)
                        {
                            data.end_time = (int) UnixTimeHelper.ConvertDataTimeLong(dtEnd);
                        }

                        data.time_span = data.end_time - data.start_time;
                        Increase(sate.Status, data.time_span, ref shutdown, ref running, ref debugging, ref free,  ref fault, ref changeDebugging);
                        canvas.list_msh.Add(data);
                    }

                    var maxTime = canvas.list_msh.Max(q => q.end_time);
                    var minTime = UnixTimeHelper.ConvertDataTimeLong(dtStart);
                    canvas.t_time_Span = maxTime - minTime;

                    var total = shutdown + running + debugging + free + fault;
                    canvas.slicesummary.Add(new SliceSummary
                    {
                        status = 0,
                        percent = Math.Round(total == 0 ? 0 : shutdown / total * 100, 2) + "%"
                    });
                    canvas.slicesummary.Add(new SliceSummary
                    {
                        status = 1,
                        percent = Math.Round(total == 0 ? 0 : running / total * 100, 2) + "%"
                    });
                    canvas.slicesummary.Add(new SliceSummary
                    {
                        status = 2,
                        percent = Math.Round(total == 0 ? 0 : debugging / total * 100, 2) + "%"
                    });
                    canvas.slicesummary.Add(new SliceSummary
                    {
                        status = 3,
                        percent = Math.Round(total == 0 ? 0 : free / total * 100, 2) + "%"
                    });
                    canvas.slicesummary.Add(new SliceSummary
                    {
                        status = 4,
                        percent = Math.Round(total == 0 ? 0 : fault / total * 100, 2) + "%"
                    });

                    result.canvas.Add(canvas);
                }

                return result;
            });
        }

        public static async Task<MachineCanvasDataInfo> GetMachineSlice(DateTime dtStart, DateTime dtEnd,
            IEnumerable<int> machineIds, int companyId, int projectId, string dateTime, int returnCategory = 1)
        {
            var response = new MachineCanvasDataInfo();
            double shutdown = 0; //关机
            double running = 0; //运行
            double debugging = 0; //调试
            double free = 0; //空闲
            double fault = 0; //故障
            double changeDebugging = 0; // 换线调试
            var repository = new SliceSateRepository(companyId, projectId);
            var sliceSates = await repository.GetCncSliceSatesAsync(machineIds,
                dtStart.ToString(ParameterConstant.DateTimeFormat), dtEnd.ToString(ParameterConstant.DateTimeFormat));
            if (sliceSates == null || !sliceSates.Any())
            {
                response.data = new MachineSateCount
                {
                    datetime = dateTime,
                    num1 = shutdown,
                    num2 = running,
                    num3 = debugging,
                    num4 = free,
                    num5 = fault,
                    num6 = changeDebugging,
                };
                response.datetime = dateTime;
                return response;
            }

            var cncSliceSates = sliceSates.ToList();
            foreach (var machineId in machineIds)
            {
                var source = cncSliceSates.Where(q => q.MachineID == machineId).ToList();
                if (!source.Any())
                {
                    continue;
                }

                foreach (var sate in source)
                {
                    var data = new MachineStatusHold
                    {
                        machine_status = sate.Status,
                        time_span = (sate.EndTime - sate.StartTime).TotalSeconds,
                        start_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.StartTime),
                        end_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.EndTime)
                    };
                    if (sate.StartTime < dtStart)
                    {
                        data.start_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtStart);
                    }
                    if (sate.EndTime > dtEnd)
                    {
                        data.end_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtEnd);
                    }
                    data.time_span = data.end_time - data.start_time;
                    Increase(sate.Status, data.time_span, ref shutdown, ref running, ref debugging, ref free, ref fault, ref changeDebugging);
                }
            }
            var totalCount = (dtEnd - dtStart).TotalSeconds * machineIds.Count();
            //shutdown = totalCount - (running + debugging + free + fault + changeDebugging);
            var total = totalCount <= 0 ? 1 : totalCount;
            if (returnCategory == 1) //返回百分比
            {
                response.data = new MachineSateCount
                {
                    datetime = dateTime,
                    num1 = totalCount <= 0 ? 100 : Math.Round(shutdown / total * 100, 2),
                    num2 = Math.Round(running / total * 100, 2),
                    num3 = Math.Round(debugging / total * 100, 2),
                    num4 = Math.Round(free / total * 100, 2),
                    num5 = Math.Round(fault / total * 100, 2),
                    num6 = Math.Round(changeDebugging / total * 100, 2),
                };
            }
            else if (returnCategory == 2) //返回 小时+百分比
            {
                response.data = new MachineSateCount
                {
                    datetime = dateTime,
                    num1 = totalCount <= 0 ? 100 : Math.Round(shutdown / total * 100, 2),
                    num2 = Math.Round(running / total * 100, 2),
                    num3 = Math.Round(debugging / total * 100, 2),
                    num4 = Math.Round(free / total * 100, 2),
                    num5 = Math.Round(fault / total * 100, 2),
                    num6 = Math.Round(changeDebugging / total * 100, 2),
                    hour1 = Math.Round(shutdown / 3600, 2),
                    hour2 = Math.Round(running / 3600, 2),
                    hour3 = Math.Round(debugging / 3600, 2),
                    hour4 = Math.Round(free / 3600, 2),
                    hour5 = Math.Round(fault / 3600, 2),
                    hour6 = Math.Round(changeDebugging / 3600, 2),
                };
            }
            response.datetime = dateTime;
            return response;
        }

        private static void Increase(int status, double value, ref double shutdown, ref double running, ref double debugging, ref double free, ref double fault, ref double changeDebugging)
        {
            switch (status)
            {
                case (int)MachineRunningStatus.Shutdown:
                    shutdown += value;
                    break;
                case (int)MachineRunningStatus.Running:
                    running += value;
                    break;
                case (int)MachineRunningStatus.Debugging:
                    debugging += value;
                    break;
                case (int)MachineRunningStatus.Free:
                    free += value;
                    break;
                case (int)MachineRunningStatus.Fault:
                    fault += value;
                    break;
                case (int)MachineRunningStatus.ChangeDebugging:
                    changeDebugging += value;
                    break;
            }
        }

        public static double GetMachineDayRunning(IEnumerable<int> machineIds, IEnumerable<CncDailySliceSate> sliceSates)
        {
            double running = 0; //运行1
            var source = sliceSates.Where(q => machineIds.Contains(q.machineID)).ToList();
            if (!source.Any())
            {
                return 0;
            }

            foreach (var dailySliceSate in sliceSates)
            {
                running += dailySliceSate.run;
            }

            return running;
        }

        /// <summary>
        /// 设备运行状态统计--铁姆肯
        /// </summary>
        /// <returns></returns>
        public static async Task<MachineCanvasDataInfo> GetMachineRunningSlice(DateTime dtStart, DateTime dtEnd,
            IEnumerable<int> machineIds, int companyId, int projectId, string dateTime)
        {
            var response = new MachineCanvasDataInfo();
            double grinding = 0; //磨削
            double repair = 0; //整修
            double ungrinding = 0; //非磨削
            var repository = new SliceSateRepository(companyId, projectId);
            var sliceSates = await repository.GetCncSliceSatesAsync(machineIds,
                dtStart.ToString(ParameterConstant.DateTimeFormat), dtEnd.ToString(ParameterConstant.DateTimeFormat), StatusCategory.HasGrinding);
            if (sliceSates == null || !sliceSates.Any())
            {
                response.data = new MachineSateCount
                {
                    datetime = dateTime,
                    num1 = grinding,
                    num2 = repair,
                    num3 = ungrinding,
                };
                response.datetime = dateTime;
                return response;
            }

            var cncSliceSates = sliceSates.ToList();
            foreach (var machineId in machineIds)
            {
                var source = cncSliceSates.Where(q => q.MachineID == machineId).ToList();
                if (!source.Any())
                {
                    continue;
                }

                foreach (var sate in source)
                {
                    var data = new MachineStatusHold
                    {
                        machine_status = sate.Status,
                        time_span = (sate.EndTime - sate.StartTime).TotalSeconds,
                        start_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.StartTime),
                        end_time = (int)UnixTimeHelper.ConvertDataTimeLong(sate.EndTime)
                    };
                    if (sate.StartTime < dtStart)
                    {
                        data.start_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtStart);
                    }
                    if (sate.EndTime > dtEnd)
                    {
                        data.end_time = (int)UnixTimeHelper.ConvertDataTimeLong(dtEnd);
                    }
                    data.time_span = data.end_time - data.start_time;
                    switch (sate.Status)
                    {
                        case 6:
                            grinding += data.time_span;
                            break;
                        case 7:
                            repair += data.time_span;
                            break;
                        case 8:
                            ungrinding += data.time_span;
                            break;
                    }
                }
            }
            var totalCount = grinding + repair + ungrinding;
            var total = totalCount <= 0 ? 1 : totalCount;
            
            response.data = new MachineSateCount
            {
                datetime = dateTime,
                num1 = totalCount <= 0 ? 100 : Math.Round(grinding / total * 100, 2),
                num2 = Math.Round(repair / total * 100, 2),
                num3 = Math.Round(ungrinding / total * 100, 2),
               
                hour1 = Math.Round(grinding / 3600, 2),
                hour2 = Math.Round(repair / 3600, 2),
                hour3 = Math.Round(ungrinding / 3600, 2),
                hour4 = Math.Round(totalCount / 3600, 2),
            };
            response.datetime = dateTime;
            return response;
        }
    }
}
