using NPOI.SS.Formula.Functions;
using NPOI.XWPF.UserModel;
using ProductionLineMonitor.Application.Services.LineService.Dtos;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace ProductionLineMonitor.Web.Services.LineService
{
    /// 
    /// 机台
    /// 
    public class MachineViewModel
    {
        public MachineViewModel()
        {
        }
        public MachineViewModel(string topic, string date, List keyInInfos, 
            List productionPlans, bool isLine)
        {
            CurrentTime = DateTime.Now;
            Date = date;
            if (!isLine)
                AnalysisTopic(topic);
            else
                Topic = topic;
            ProductionPlans = productionPlans;
            KeyInInfos = keyInInfos;
            LoadOutPutPerHours = MesApiService.GetOutPutPerHours(Topic, Date);
            if (LoadOutPutPerHours.Count() < 24)
            {
                Statistics = new List();
                return;
            }
            WashOutPutPerHours();
            CalculateV1();
        }
        /// 
        /// 解析Topic
        /// 
        /// 
        protected void AnalysisTopic(string topic)
        {
            Topic = topic;
            int index = topic.IndexOf('-');
            Floor = Convert.ToInt16(topic.Substring(index + 1, 1));
            Line = Convert.ToInt16(topic.Substring(index - 2, 2));
            index = topic.IndexOf("Data");
            Type = topic[..index];
        }
        private string _date = string.Empty;
        /// 
        /// 日期
        /// 
        public string Date
        {
            get
            {
                return _date;
            }
            set
            {
                _date = value;
                StartTime = Convert.ToDateTime($"{_date} 08:00:00");
                EndTime = StartTime.AddDays(1);
            }
        }
        public DateTime StartTime { get; set; }
        
        public DateTime EndTime { get; set; }
        /// 
        /// 当前时间
        /// 
        public DateTime CurrentTime { get; set; }
        /// 
        /// topic
        /// 
        public string Topic { get; set; } = string.Empty;
        /// 
        /// 楼层
        /// 
        public int Floor { get; set; }
        /// 
        /// 线别
        /// 
        public int Line { get; set; }
        /// 
        /// 类型
        /// 
        public string Type { get; set; } = string.Empty;
        /// 
        /// 生产计划
        /// 
        public List ProductionPlans { get; set; }
            = new List();
        /// 
        /// key in 的异常
        /// 
        public List KeyInInfos { get; set; }
            = new List();
        /// 
        /// 小时产能
        /// 
        public List LoadOutPutPerHours { get; set; }
            = new List();
        /// 
        /// 清理后小时产能
        /// 
        public List NewOutPutPerHours { get; set; }
            = new List();
        /// 
        /// 统计
        /// 
        public List Statistics { get; set; }
            = new List();
        /// 
        /// 获取小时产能
        /// 
        public void UpdateModuleType()
        {
            if (Type != "AG"
                && Type != "FPL"
                && Type != "BT"
                && Type != "PS"
                && Type != "EC"
                && Type != "TP")
                return;
            string topic = $"FOGData#{Line}#{Line}-{Floor}FOG01";
            if (Line < 10)
                topic = $"FOGData#{Line}#0{Line}-{Floor}FOG01";
            var outs = MesApiService.GetOutPutPerHours(topic, Date);
            foreach (var item in outs)
            {
                var t = LoadOutPutPerHours.Find(x => x.DataTime == item.DataTime);
                if (t != null)
                    t.ModuleType = item.ModuleType;
            }
        }
        /// 
        /// 根据 key in 时间清洗小时产能
        /// 
        public void WashOutPutPerHours()
        {
            /*
                    0:  品质异常停线                   
                    1:  宕机
                    2:  换线                             
                    3:  实验
                    4:  W/F送样
                    5:  物料缺料或生管调整影响
                    6:  放假
                    7:  停电气等停线
                    8:  换耗材类
                    9:  停机未生产              
                    10: 效率爬升        
             */
            NewOutPutPerHours = new List();
            if (LoadOutPutPerHours == null)
            {
                return;
            }
            if (LoadOutPutPerHours.Count() == 0)
            {
                return;
            }
            foreach (var item in LoadOutPutPerHours)
            {
                NewMachineDayOutPutPerHour outPutPerHour = new NewMachineDayOutPutPerHour()
                {
                    DataTime = item.DataTime,
                    ModuleType = item.ModuleType,
                    OutPut = item.OutPut,
                    AutoRunTime = item.AutoRunTime,
                    AlarmTime = item.AlarmTime,
                    IdleTime = item.IdleTime,
                    IdleTimeDownstream = item.IdleTimeDownstream,
                    IdleTimeUpstream = item.IdleTimeUpstream,
                    AlarmSum = item.AlarmSum,
                    IdleTimeSelf = item.IdleTimeSelf,
                    TargetTT = item.TargetTT,
                    ActualTT = item.ActualTT,
                    LoadMATSum = item.LoadMATSum,
                    LoadMATTime = item.LoadMATTime,
                    LoadTime = 0,
                };
                if (item.DataTime > DateTime.Now)
                {
                    outPutPerHour.ModuleType = "";
                }
                NewOutPutPerHours.Add(outPutPerHour);
            }
            if (NewOutPutPerHours.Count == 0)
                return;
            foreach (var key in KeyInInfos)
            {   
                if (key.KeyInType == 2 || key.KeyInType == 3 || key.KeyInType == 4 ||
                    key.KeyInType == 6 || key.KeyInType == 7 || key.KeyInType == 9)
                {
                    if (key.StartTime == null)
                        continue;
                    if (key.EndTime == null || key.EndTime.Value.Year < 2000)
                    {
                        if (key.StartTime.Value.Hour >= 0 || key.StartTime.Value.Hour <= 7)
                            key.EndTime = Convert.ToDateTime($"{key.StartTime.Value:yyyy-MM-dd} 08:00:00");
                        else
                            key.EndTime = Convert.ToDateTime($"{key.StartTime.Value.AddDays(1):yyyy-MM-dd} 08:00:00");
                        if (key.EndTime > EndTime)
                            key.EndTime = EndTime;
                    }
                    var ds = GetLoadTime(key.StartTime.Value, key.EndTime.Value);
                    for (int i = 0; i < ds.Length; i++)
                    {
                        if (ds[i] > 0)
                        {
                            if (ds[i] == 60)
                            {
                                NewOutPutPerHours[i].ModuleType = "";
                                NewOutPutPerHours[i].OutPut = 0;
                                NewOutPutPerHours[i].AutoRunTime = 0;
                                NewOutPutPerHours[i].AlarmTime = 0;
                                NewOutPutPerHours[i].IdleTime = 0;
                                NewOutPutPerHours[i].IdleTimeDownstream = 0;
                                NewOutPutPerHours[i].IdleTimeUpstream = 0;
                                NewOutPutPerHours[i].AlarmSum = 0;
                                NewOutPutPerHours[i].IdleTimeSelf = 0;
                                NewOutPutPerHours[i].TargetTT = 0;
                                NewOutPutPerHours[i].ActualTT = 0;
                                NewOutPutPerHours[i].LoadMATSum = 0;
                                NewOutPutPerHours[i].LoadMATTime = 0;
                                NewOutPutPerHours[i].LoadTime = 60;
                            }
                            else
                            {
                                NewOutPutPerHours[i].LoadTime += (int)ds[i];
                                if (NewOutPutPerHours[i].LoadTime > 60)
                                    NewOutPutPerHours[i].LoadTime = 60;
                            }
                        }
                    }
                }
            }
        }
        private double[] GetLoadTime(DateTime startTime, DateTime endTime)
        {
            // [00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
            // [08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 00 01 02 03 04 05 06 07]
            // [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
            double[] loadTimes = new double[24];
            startTime = Convert.ToDateTime($"{startTime:yyyy-MM-dd HH:mm:00}");
            endTime = Convert.ToDateTime($"{endTime:yyyy-MM-dd HH:mm:00}");
            if ((endTime - startTime).TotalMinutes <= 60 && endTime.Hour == startTime.Hour)
            {
                loadTimes[endTime.Hour >= 8 ? endTime.Hour - 8 : endTime.Hour + 16] = Math.Ceiling((endTime - startTime).TotalMinutes);
                return loadTimes;
            }
            DateTime d1 = Convert.ToDateTime($"{startTime.AddHours(1):yyyy-MM-dd HH}:00:00");
            DateTime d2 = Convert.ToDateTime($"{endTime:yyyy-MM-dd HH}:00:00");
            for (DateTime dt = d1; dt < d2; dt = dt.AddHours(+1))
            {
                loadTimes[dt.Hour >= 8 ? dt.Hour - 8 : dt.Hour + 16] = 60;
            }
            loadTimes[startTime.Hour >= 8 ? startTime.Hour - 8 : startTime.Hour + 16] = Math.Ceiling((d1 - startTime).TotalMinutes);
            if (endTime > d2)
                loadTimes[endTime.Hour >= 8 ? endTime.Hour - 8 : endTime.Hour + 16] = Math.Ceiling((endTime - d2).TotalMinutes);
            return loadTimes;
        }
        /// 
        /// 计算
        /// 
        public void Calculate()
        {
            int len = 10;
            if (NewOutPutPerHours.Count() <= 0)
            {
                return;
            }
            IEnumerable moduleTypes = NewOutPutPerHours
                    .Where(x => x.ModuleType != null && x.ModuleType != "" && x.ModuleType.Length >= len)
                    .Select(x => x.ModuleType[..len])
                    .Distinct();
            if (moduleTypes.Count() == 0)
            {
                Statistic statistic = new Statistic();
                Statistics.Add(statistic);
                return;
            }
            foreach (var moduleType in moduleTypes)
            {
                string str = moduleType[..len];
                Statistic statistic = new Statistic()
                {
                    ModuleType = str
                };
                var plan = ProductionPlans.Where(
                    x =>
                    x.ModuleType != "" &&
                    x.ModuleType.Length >= 8 &&
                    x.ModuleType[..len] == str).ToList();
                if (plan != null && plan.Count() > 0)
                {
                    statistic.Capa = plan[0].Capa == -1 ? 0 : plan[0].Capa;
                    statistic.TT = plan[0].TT == -1 ? 0 : plan[0].TT;
                    statistic.PlanCapacity = plan.Where(x => x.PlanCapacity > 0).Select(x => x.PlanCapacity).Sum();
                    var newOutPuts = NewOutPutPerHours.Where(
                        x =>
                        x.ModuleType != null &&
                        x.ModuleType != "" &&
                        x.ModuleType[..len] == str &&
                        x.DataTime <= CurrentTime).ToList();
                    statistic.RunTime = newOutPuts.Sum(x => x.AutoRunTime);
                    double loadTime = newOutPuts.Sum(x => x.LoadTime);
                    DateTime endTime = Convert.ToDateTime($"{Date} 08:00:00").AddDays(1);
                    if (CurrentTime > endTime)
                        statistic.LoadTime = newOutPuts.Count() * 60 - loadTime;
                    else
                        statistic.LoadTime = (newOutPuts.Count() - 1) * 60 - loadTime
                                + Math.Round((CurrentTime - newOutPuts.Last().DataTime).TotalMinutes);
                    statistic.DownTime = newOutPuts.Sum(x => x.AlarmTime);
                    statistic.IdelTime = statistic.LoadTime - statistic.DownTime - statistic.RunTime;
                    statistic.Capacity = newOutPuts.Sum(x => x.OutPut);
                    statistic.MorningShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 8 && x.DataTime.Hour < 20).Sum(x => x.OutPut);
                    statistic.NightShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 20 || x.DataTime.Hour < 7).Sum(x => x.OutPut);
                    statistic.Availability = Math.Round(statistic.LoadTime == 0 ? 0 : statistic.RunTime / statistic.LoadTime, 2);
                    statistic.Performance = Math.Round(statistic.RunTime == 0 ? 0 : statistic.TT / 60 * statistic.Capacity / statistic.RunTime, 2);
                    statistic.Quality = 1;
                    statistic.OEE = Math.Round(statistic.Availability * statistic.Performance * statistic.Quality, 2);
                }
                else
                {
                    var newOutPuts = NewOutPutPerHours.Where(
                        x =>
                        x.ModuleType != null &&
                        x.ModuleType != "" &&
                        x.ModuleType[..len] == str &&
                        x.DataTime <= CurrentTime).ToList();
                    statistic.RunTime = newOutPuts.Sum(x => x.AutoRunTime);
                    double loadTime = newOutPuts.Sum(x => x.LoadTime);
                    DateTime endTime = Convert.ToDateTime($"{Date} 08:00:00").AddDays(1);
                    if (CurrentTime > endTime)
                        statistic.LoadTime = newOutPuts.Count() * 60 - loadTime;
                    else
                        statistic.LoadTime = (newOutPuts.Count() - 1) * 60 - loadTime
                                + Math.Round((CurrentTime - newOutPuts.Last().DataTime).TotalMinutes);
                    statistic.DownTime = newOutPuts.Sum(x => x.AlarmTime);
                    statistic.IdelTime = statistic.LoadTime - statistic.DownTime - statistic.RunTime;
                    statistic.Capacity = newOutPuts.Sum(x => x.OutPut);
                    statistic.MorningShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 8 && x.DataTime.Hour < 20).Sum(x => x.OutPut);
                    statistic.NightShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 20 || x.DataTime.Hour < 7).Sum(x => x.OutPut);
                    statistic.Availability = Math.Round(statistic.LoadTime == 0 ? 0 : statistic.RunTime / statistic.LoadTime, 2);
                }
                Statistics.Add(statistic);
            }
        }
        public void CalculateV1()
        {
            IEnumerable moduleTypes = ProductionPlans
                    .Where(x => x.ModuleType != null && x.ModuleType != "")
                    .Select(x => x.ModuleType)
                    .Distinct();
            if (moduleTypes.Count() == 0)
            {
                Statistic statistic = new Statistic();
                Statistics.Add(statistic);
                return;
            }
            foreach (var moduleType in moduleTypes)
            {
                Statistic statistic = new Statistic()
                {
                    ModuleType = moduleType
                };
                var plan = ProductionPlans.Where(
                    x =>
                    x.ModuleType != "" &&
                    x.ModuleType == moduleType).ToList();
                if (plan == null || plan.Count() <= 0)
                {
                    Statistics.Add(statistic);
                    continue;
                }
                statistic.Capa = plan[0].Capa == -1 ? 0 : plan[0].Capa;
                statistic.TT = plan[0].TT == -1 ? 0 : plan[0].TT;
                statistic.PlanCapacity = plan.Where(x => x.PlanCapacity > 0).Select(x => x.PlanCapacity).Sum();
                var newOutPuts = NewOutPutPerHours.Where(
                    x =>
                    x.ModuleType != null &&
                    x.ModuleType != "" &&
                    x.ModuleType.Length >= moduleType.Length &&
                    x.ModuleType[..moduleType.Length] == moduleType &&
                    x.DataTime <= CurrentTime).ToList();
                if (newOutPuts == null || newOutPuts.Count <= 0)
                {
                    Statistics.Add(statistic);
                    continue;
                }
                statistic.RunTime = newOutPuts.Sum(x => x.AutoRunTime);
                double loadTime = newOutPuts.Sum(x => x.LoadTime);
                DateTime endTime = Convert.ToDateTime($"{Date} 08:00:00").AddDays(1);
                if (CurrentTime > endTime)
                    statistic.LoadTime = newOutPuts.Count() * 60 - loadTime;
                else
                    statistic.LoadTime = (newOutPuts.Count() - 1) * 60 - loadTime
                            + Math.Round((CurrentTime - newOutPuts.Last().DataTime).TotalMinutes);
                statistic.DownTime = newOutPuts.Sum(x => x.AlarmTime);
                statistic.IdelTime = statistic.LoadTime - statistic.DownTime - statistic.RunTime;
                statistic.Capacity = newOutPuts.Sum(x => x.OutPut);
                statistic.MorningShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 8 && x.DataTime.Hour < 20).Sum(x => x.OutPut);
                statistic.NightShiftCapacity = newOutPuts.Where(x => x.DataTime.Hour >= 20 || x.DataTime.Hour < 7).Sum(x => x.OutPut);
                statistic.Availability = Math.Round(statistic.LoadTime == 0 ? 0 : statistic.RunTime / statistic.LoadTime, 2);
                statistic.Performance = Math.Round(statistic.RunTime == 0 ? 0 : statistic.TT / 60 * statistic.Capacity / statistic.RunTime, 2);
                statistic.Quality = 1;
                statistic.OEE = Math.Round(statistic.Availability * statistic.Performance * statistic.Quality, 2);
                Statistics.Add(statistic);
            }
        }
    }
}