using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.CncRepository.Entities;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Request;
using Siger.Middlelayer.CncRepository.Response;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Dapper;
using Siger.Middlelayer.Dapper.Utilities.Slice;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.Share.Models;
using Siger.Middlelayer.Share.Utilities;

namespace Siger.ApiCNC.Controllers
{
    /// <summary>
    /// 排程v1.4
    /// </summary>
    public class SchedulingController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IProduceScheduleRepository _scheduleRepository;
        private readonly IProductionBeatSetRepository _beatSetRepository;
        private readonly IProductPlanRepository _planRepository;
        private readonly IProductionTimeRepository _timeRepository;
        private readonly ISigerProjectMachineRepository _machineRepository;
        private readonly IProductPlanDetailRepository _planDetailRepository;
        private readonly IProductionAllocationRepository _allocationRepository;
        private readonly ISigerProjectProductReport _reportRepository;
        private readonly IProductionTimeAllocationRepository _timeAllocationRepository;
        public SchedulingController(IUnitOfWork unitOfWork, IProduceScheduleRepository scheduleRepository, IProductionBeatSetRepository beatSetRepository,
            IProductPlanRepository planRepository, IProductionTimeRepository timeRepository, ISigerProjectMachineRepository machineRepository, IProductionTimeAllocationRepository timeAllocationRepository,
            IProductPlanDetailRepository planDetailRepository, IProductionAllocationRepository allocationRepository, ISigerProjectProductReport reportRepository)
        {
            _unitOfWork = unitOfWork;
            _scheduleRepository = scheduleRepository;
            _beatSetRepository = beatSetRepository;
            _planRepository = planRepository;
            _timeRepository = timeRepository;
            _machineRepository = machineRepository;
            _planDetailRepository = planDetailRepository;
            _allocationRepository = allocationRepository;
            _reportRepository = reportRepository;
            _timeAllocationRepository = timeAllocationRepository;
        }

        [HttpGet]
        public IActionResult GetRoutes(int planId, int levelId)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            var routes = _scheduleRepository.GetRoutes(plan.product_id, levelId, ProjectId).OrderBy(m => m.serialnumber);
            
            if (!routes.Any())
            {
               throw new BadRequestException(CncEnum.RoutesNotFound);
            }
            var responses = new List<ResponseGetProductRouteInfo>();

            var beats = _beatSetRepository.GetBeatInfos(plan.product_id, routes.Select(m => m.sectionid).ToList(), ProjectId);
            if (routes.Count() != beats.Count())
            {
                throw new BadRequestException(CncEnum.MachineCycleTimeNotFound);
            }
            foreach (var route in routes)
            {
                var beat = beats.FirstOrDefault(m => m.sectionId == route.sectionid && m.productId == plan.product_id);
                responses.Add(new ResponseGetProductRouteInfo
                {
                    cycletime = beat?.cycleTime ?? 0,
                    sectionid = route.sectionid,
                    sectionname = route.sectionname,
                    serialnumber = route.serialnumber
                });
            }
            return new ObjectResult(responses);
        }

        [HttpPost]
        public IActionResult ExecuteSchedule([FromBody]RequestExecuteSchedule request)
        {
            if (request.orders == null || !request.orders.Any())
            {
                throw new BadRequestException(CncEnum.BatchMustGreaterZero);
            }
            var plan = _planRepository.Get(request.planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            if (plan.status != (int) PlanProcess.UnPlan && plan.status != (int)PlanProcess.Stop)
            {
                throw new BadRequestException(CncEnum.PlanHasExist);
            }

            var sectionIds = request.orders.Select(m => m.sectionId).Distinct();
            var times = GetRestTimesBySections(sectionIds).ToList(); //全部的休息时间
            var transfers = _allocationRepository.GetList(m =>
                sectionIds.Contains(m.section_id) && m.status == (int) RowState.Valid && m.projectid == ProjectId).ToList();

            var schedules = _scheduleRepository.GetList(m =>
                    sectionIds.Contains(m.sectionId) && m.status == (int) RowState.Valid && m.projectId == ProjectId).ToList(); //当前的排产

            var responses = new List<ResponseExecuteSchedule>();

            var now = UnixTimeHelper.GetNow();

            var levelIds = request.orders.Select(m => m.levelId).Distinct();
            foreach (var levelId in levelIds)
            {
                var orders = request.orders.Where(q => q.levelId == levelId);
                var dtStart = now;
                foreach (var order in orders)
                {
                    var transfer = transfers.FirstOrDefault(q => q.section_id == order.sectionId);
                    var response = new ResponseExecuteSchedule
                    {
                        batch = order.batch,
                        count = order.count,
                        cycleTime = order.cycleTime,
                        levelId = order.levelId,
                        orderNumber = order.orderNumber,
                        sectionId = order.sectionId,
                        sectionName = order.sectionName,
                        serialNumber = order.serialNumber,
                    };
                    
                    var sectionStartTime = now; //设备最早可用时间

                    //不同的产线出现同一设备的情形
                    var tempOrder = responses.Where(q => q.sectionId == order.sectionId).OrderByDescending(q => q.endTime).FirstOrDefault();
                    if (tempOrder != null)
                    {
                        //dtStart = dtStart > tempOrder.endTime ? dtStart : tempOrder.endTime;
                        dtStart = tempOrder.endTime;
                        sectionStartTime = sectionStartTime > tempOrder.endTime ? sectionStartTime : tempOrder.endTime;
                    }
                    //同一个工令号的结束时间
                    tempOrder = responses.Where(q => q.orderNumber == order.orderNumber).OrderByDescending(q => q.endTime).FirstOrDefault();
                    if (tempOrder != null)
                    {
                        dtStart = dtStart > tempOrder.endTime ? dtStart : tempOrder.endTime;
                        var oos = responses.Where(q => q.orderNumber == tempOrder.orderNumber).OrderBy(q => q.serialNumber).ToList();
                        var oo = oos.FirstOrDefault(q => q.serialNumber == tempOrder.serialNumber);
                        if (oo != null)
                        {
                            var tr = transfers.FirstOrDefault(q => q.section_id == oo.sectionId);
                            if (tr != null)
                            {
                                dtStart += tr.transfer_time;
                            }
                        }
                    }

                    var lastSchedule = schedules.Where(m => m.sectionId == order.sectionId).OrderByDescending(m => m.endTime).FirstOrDefault();
                    if (lastSchedule != null)
                    {
                        dtStart = dtStart > lastSchedule.endTime ? dtStart : lastSchedule.endTime;
                        sectionStartTime = sectionStartTime > lastSchedule.endTime ? sectionStartTime : lastSchedule.endTime;
                    }

                    //换型时间，该设备前一个工单生产的产品是否与当前的产品相同
                    if (tempOrder == null) //第二个section不需要再加换型时间
                    {
                        var sch = _scheduleRepository.GetList(q => q.sectionId == order.sectionId && q.status == (int)RowState.Valid && q.projectId == ProjectId)
                            .OrderByDescending(q => q.endTime).FirstOrDefault();
                        if (sch != null)
                        {
                            var planDetail = _planDetailRepository.Get(q => q.id == sch.plandetail_id && q.status == (int)RowState.Valid && q.projectId == ProjectId);
                            if (planDetail != null)
                            {
                                var lastPlan = _planRepository.Get(q => q.id == planDetail.planId && q.status == (int)RowState.Valid && q.projectid == ProjectId);
                                if (lastPlan != null)
                                {
                                    if (lastPlan.product_id != plan.product_id)
                                    {
                                        var beat = _beatSetRepository.Get(q => q.projectID == ProjectId && q.section_id == order.sectionId
                                                                     && q.drawing_number == plan.draw_number && q.status == (int)RowState.Valid
                                                                     && q.start_time <= DateTime.Now && q.end_time >= DateTime.Now);
                                        if (beat != null)
                                        {
                                            dtStart += beat.changemodeltime;
                                            sectionStartTime += beat.changemodeltime;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    //工序转移时间
                    double totlaCycleTime = order.cycleTime * order.count;
                    
                    if (transfer != null && transfer.rate > 0)
                    {
                        totlaCycleTime = totlaCycleTime / 100 * transfer.rate;
                    }
                    var total = int.Parse(totlaCycleTime.ToString(CultureInfo.InvariantCulture));

                    var dtEnd = dtStart + total;
                    if (request.excludeRestTime == 1) //是否排除休息时间
                    {
                        var sectionTimes = times.Where(q => q.SectionId == order.sectionId).ToList();
                        RestTimeManager.GetStartTime(sectionTimes,  ref dtStart); // 重置开始时间
                        dtEnd = RestTimeManager.GetEndTime(sectionTimes,  dtStart, total);
                    }

                    response.sectionStartTime = sectionStartTime;
                    response.startTime = dtStart;
                    response.endTime = dtEnd;
                    responses.Add(response);
                    
                    dtStart = dtEnd;
                }
            }

            //赋值产线最早和最晚时间
            var result = new List<ResponseExecuteSchedule>();
            foreach (var response in responses)
            {
                var entity = Mapper<ResponseExecuteSchedule, ResponseExecuteSchedule>.Map(response);
                entity.levelStartTime = responses.Where(q => q.orderNumber == response.orderNumber).Min(q => q.startTime);
                entity.levelEndTime = responses.Where(q => q.orderNumber == response.orderNumber).Max(q => q.endTime);
                result.Add(entity);
            }

            return new ObjectResult(result);
        }

        private IEnumerable<MachineRestInfo> GetRestTimesBySections(IEnumerable<int> sectionIds)
        {
            var result = new List<MachineRestInfo>();
            foreach (var sectionId in sectionIds)
            {
                var machine = _machineRepository.GetNCMachineBySectionId(sectionId, ProjectId);
                if (machine != null)
                {
                    var times = _timeRepository.GetList(m => m.machineid == machine.id && 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 = machine.id,
                            SectionId = sectionId,
                            TimeType = (TimeType)time.typeid
                        });
                    }
                }
            }

            return result;
        }

        [HttpPost]
        public IActionResult AddSchedule([FromBody]RequestAddSchedule request)
        {
            if (request.orders == null || !request.orders.Any())
            {
                throw new BadRequestException(CncEnum.BatchMustGreaterZero);
            }
            var plan = _planRepository.Get(request.planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            if (plan.status != (int)PlanProcess.UnPlan && plan.status != (int)PlanProcess.Stop)
            {
                throw new BadRequestException(CncEnum.PlanHasExist);
            }

            var orderNumbers = request.orders.Select(m => m.orderNumber).Distinct();
            foreach (var orderNumber in orderNumbers)
            {
                var detail = request.orders.First(m => m.orderNumber == orderNumber);
                var sectionStartTime = request.orders.Where(m => m.orderNumber == orderNumber).OrderBy(m => DateTime.Parse(m.startTime)).First();
                var sectionEndTime = request.orders.Where(m => m.orderNumber == orderNumber).OrderByDescending(m => DateTime.Parse(m.endTime)).First();
                var planDetail = new siger_project_product_plan_detail
                {
                    addTime = DateTime.Now,
                    levelId = detail.levelId,
                    startTime = UnixTimeHelper.GetUnixByShortDate(sectionStartTime.startTime),
                    endTime = UnixTimeHelper.GetUnixByShortDate(sectionEndTime.endTime),
                    orderNumber = orderNumber,
                    planId = request.planId,
                    projectId = ProjectId,
                    quantity = detail.count,
                };
                _planDetailRepository.Insert(planDetail);
                _unitOfWork.Commit();

                var schedules = request.orders.Where(m => m.orderNumber == orderNumber);
                foreach (var schedule in schedules)
                {
                    var entity = new siger_project_produce_schedule
                    {
                        addTime = DateTime.Now,
                        endTime = UnixTimeHelper.GetUnixByShortDate(schedule.endTime),
                        projectId = ProjectId,
                        sectionId = schedule.sectionId,
                        startTime = UnixTimeHelper.GetUnixByShortDate(schedule.startTime),
                        plandetail_id = planDetail.id,
                        cycle_time = schedule.cycleTime
                    };
                    _scheduleRepository.Insert(entity);
                }
            }

            plan.status = (int) PlanProcess.HasPlan;
            _planRepository.Update(plan);

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }


        [HttpGet]
        public IActionResult StopSchedule(int planId)
        {
            var plan = _planRepository.Get(planId);
            if (plan == null)
            {
                throw new BadRequestException(CncEnum.PlanNotFound);
            }

            if (plan.status != (int)PlanProcess.HasPlan)
            {
                throw new BadRequestException(CncEnum.PlanCannotStop);
            }

            plan.status = (int) PlanProcess.Stop;
            _planRepository.Update(plan);

            //工令单
            var orders = _planDetailRepository.GetList(m => m.planId == planId && m.status == (int) RowState.Valid).ToList();
            foreach (var order in orders)
            {
                //order.status = (int) RowState.Invalid;
                //_planDetailRepository.Update(order);

                //排产
                var schedules = _scheduleRepository.GetList(m => m.plandetail_id == order.id && m.status == (int) RowState.Valid).ToList();
                foreach (var schedule in schedules)
                {
                    schedule.status = (int)RowState.Invalid;
                    _scheduleRepository.Update(schedule);
                }
            }

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="requestPlanId"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetPlanDatailsForPrint([FromBody]RequestplanId requestPlanId)
        {
            if (requestPlanId.planId==null)
                throw new BadRequestException(RequestEnum.ParameterMiss);

            var result = new List<ResponsePlanDatailsForPrint>();
            foreach (var planId in requestPlanId.planId)
            {
                var plan = _planRepository.Get(planId);
                if (plan == null)
                {
                    throw new BadRequestException(CncEnum.PlanNotFound);
                }

                if (plan.status == (int)PlanProcess.UnPlan)
                {
                    throw new BadRequestException(CncEnum.WorkOrderCannotPrint);
                }
                var planDetails = _planDetailRepository.GetList(m => m.planId == planId && m.status == (int)RowState.Valid && m.projectId == ProjectId);
                var levelIds = planDetails.Select(m => m.levelId).Distinct().ToList();
                var levels = _planDetailRepository.GetSectionTitles(levelIds, ProjectId);
                foreach (var planDetail in planDetails.ToList())
                {
                    var section = levels.FirstOrDefault(q => q.id == planDetail.levelId);
                    var response = new ResponsePlanDatailsForPrint
                    {
                        count = planDetail.quantity,
                        draw_number = plan.draw_number,
                        levelName = section != null ? section.title : "",
                        orderNumber = planDetail.orderNumber,
                        partnumber = plan.partnumber,
                        product_code = plan.product_code,
                        product_name = plan.product_name,
                        delivery_time = plan.delivery_time
                    };

                    var schedules = _scheduleRepository.GetList(m =>
                            m.plandetail_id == planDetail.id && m.status == (int)RowState.Valid &&
                            m.projectId == ProjectId)
                        .ToList();
                    var i = 1;
                    var sectionIds = schedules.Select(m => m.sectionId).Distinct().ToList();
                    var sections = _planDetailRepository.GetSectionTitles(sectionIds, ProjectId);
                    foreach (var schedule in schedules)
                    {
                        var sectionEntity = sections.FirstOrDefault(q => q.id == schedule.sectionId);
                        response.routes.Add(new RouteForPrint
                        {
                            cycletime = schedule.cycle_time,
                            orderNumber = planDetail.orderNumber,
                            plan_end = schedule.endTime,
                            sectionname = sectionEntity != null ? sectionEntity.title : "",
                            remark = "",
                            serialnumber = i
                        });
                        i++;
                    }

                    result.Add(response);
                }
            }
            return new ObjectResult(result);
        }

        /// <summary>
        /// 设备负载分析
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> GetMachineLoadAnalysis([FromBody] RequestMachineLoadAnalysis request)
        {
            var dtStart = DateTime.Parse(request.startTime);
            var dtEnd = DateTime.Parse(request.endTime).AddDays(1).AddSeconds(-1);

            var result = new List<ResponseMachineLoadAnalysis>();

            var validMachines = _machineRepository.GetNCLevelSectionNames(request.sectionId.ToInt(), ProjectId);
            var validMachineIds = validMachines.Select(m => m.machine_id).Distinct().ToList();

            var repository = new SliceSateRepository(CompanyId, ProjectId);
            var sliceSates = repository.GetCncSliceSates(validMachineIds, 
                dtStart.ToString(ParameterConstant.DateTimeFormat), dtEnd.ToString(ParameterConstant.DateTimeFormat));
            foreach (var machineId in validMachineIds)
            {
                var machine = validMachines.FirstOrDefault(q =>q.machine_id == machineId);
                if (machine == null)
                {
                    continue;
                }
                var response = new ResponseMachineLoadAnalysis { title = machine.lastSecondSectionTitle + "-" + machine.lastSectionTitle };

                var machines = new List<int> {machineId};
                //var times = _timeRepository.GetRestTimesByMachine(machines, ProjectId);
                var times = _timeAllocationRepository.GetRestTimesByMachine(machines, ProjectId);
                response.standardHours = Math.Round(RestTimeManager.GetRestSeconds(times, dtStart, dtEnd) / 3600 ,1); //标准工时

                response.planHours = await GetPlanHours(machineId, dtStart, dtEnd); // 任务工时 = 计划数量*标准节拍

                response.actualHours = Math.Round(SliceManager.GetRunTime(dtStart, dtEnd, sliceSates, machines) / 60 / 60, 1); // 设备运行时间

                if (response.standardHours > 0)
                {
                    response.rate = Math.Round(response.planHours / response.standardHours * 100, 2);
                }

                result.Add(response);
            }

            return new ObjectResult(result);
        }

        /// <summary>
        /// 取工站全部的排产时间
        /// </summary>
        /// <param name="machineId"></param>
        /// <param name="dtStart"></param>
        /// <param name="dtEnd"></param>
        /// <returns></returns>
        private async Task<double> GetPlanHours(int machineId, DateTime dtStart, DateTime dtEnd)
        {
            var sectionIds = _machineRepository.GetNCSectionIdsByMahcineIds(new List<int> {machineId}, ProjectId).ToList();
            if (!sectionIds.Any())
            {
                return 0;
            }
            double totalSecond = 0;
            var unixStart = UnixTimeHelper.GetUnixByShortDate(dtStart.ToString());
            var unixEnd = UnixTimeHelper.GetUnixByShortDate(dtEnd.ToString());

            var schedules = await _scheduleRepository.GetListAsync(q =>
                q.projectId == ProjectId && sectionIds.Contains(q.sectionId) && q.status == (int) RowState.Valid && q.startTime >= unixStart
                && q.startTime <= unixEnd);

            await Task.Run(() =>
            {
                foreach (var schedule in schedules.ToList())
                {
                    var planDetail = _planDetailRepository.Get(q => q.id == schedule.plandetail_id);
                    if (planDetail != null && planDetail.status == (int) RowState.Valid)
                    {
                        totalSecond += planDetail.quantity * schedule.cycle_time;
                    }
                }
            });

            return Math.Round(totalSecond / 60 / 60, 1);
        }

        /// <summary>
        /// 冲突列表
        /// </summary>
        /// <param name="sectionid"></param>
        /// <param name="page"></param>
        /// <param name="pagesize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetScheduleCrash(int sectionid, int page = 1, int pagesize = 10)
        {
            var response = new List<ResponseGetCrashList>();

            var schedules = _scheduleRepository.GetCrashLists(sectionid, ProjectId);
            if (!schedules.Any())
            {
                return new ObjectResult(response);
            }
            var validMachines = _machineRepository.GetNCLevelSectionNames(sectionid, ProjectId);
            //计划时间冲突
            var sectionIds = schedules.Select(q => q.sectionId).Distinct();
            foreach (var sectionId in sectionIds)
            {
                var sectionSchedules = schedules.Where(q => q.sectionId == sectionId).OrderBy(m => m.startTime).ToList();
                if (sectionSchedules.Count < 2)
                {
                    continue;
                }
                for (var i = 0; i < sectionSchedules.Count - 1; i++)
                {
                    var sch1 = sectionSchedules[i];
                    var sch2 = sectionSchedules[i + 1];
                    if ((sch2.startTime > sch1.startTime && sch2.startTime < sch1.endTime) || (sch2.endTime > sch1.startTime && sch2.endTime < sch1.endTime))
                    {
                        sch2.reason = 1;
                        sch2.relationCode = sch1.orderNumber;

                        var machine = validMachines.FirstOrDefault(q => q.section_id == sectionId);
                        sch2.location = machine == null ? "" : machine.lastSecondSectionTitle + "-" + machine.lastSectionTitle;
                        response.Add(sch2);
                    }
                }
            }

            //工单延误
            //var planIds = schedules.Select(q => q.planId).Distinct();
            //foreach (var planId in planIds)
            //{
            //    var plans = schedules.Where(q => q.planId == planId);
            //    foreach (var plan in plans)
            //    {
            //        if (plan.endTime > plan.delivery_time)
            //        {
            //            plan.reason = 2;
            //            plan.relationCode = "NA";
            //            plan.location = string.Join('-', _allocationRepository.GetLevelSectionTitles(plan.sectionId, ProjectId));
            //            response.Add(plan);
            //        }
            //    }
            //}

            var entities = response.Skip((page - 1) * pagesize).Take(pagesize).ToList();

            return new PagedObjectResult(entities, response.Count, page, pagesize);
        }

        /// <summary>
        /// 工单甘特图
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetWorkOrderGante([FromBody]RequestWorkOrderGante request)
        {
            var start = UnixTimeHelper.GetUnixByDate(request.startTime);
            var end = UnixTimeHelper.GetUnixByDate(request.endTime) + 86400 - 1;

            var responses = _planDetailRepository.GetWorkOrderGante(request.productName, request.draw_number,
                request.code, request.status.ToInt(), start, end, ProjectId);

            var result = new List<ResponseWorkOrderGante>();
            foreach (var response in responses)
            {
                var gante = Mapper<ResponseWorkOrderGante, ResponseWorkOrderGante>.Map(response);
                gante.partialFill = response.quantity == 0
                    ? 0
                    : decimal.Round((decimal) response.ok_number / response.quantity, 4);

                var detailes = _planDetailRepository.GetList(q => q.planId == response.id && q.status == (int) RowState.Valid);
                if (detailes.Any())
                {
                    gante.startTime = detailes.Min(q => q.startTime);
                    gante.endTime = detailes.Max(q => q.endTime);
                }

                result.Add(gante);
            }

            return new ObjectResult(result);
        }

        /// <summary>
        /// 设备甘特图
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetMachineGante(int sectionId)
        {
            var schedules = _scheduleRepository.GetMachineGante(sectionId, ProjectId);
            var responses = new List<ResponseGetMachineGante>();

            var groups = from p in schedules
                         group p by new
                {
                    p.sectionId,
                }
                into g
                select g;

            var i = 0;

            var validMachines = _machineRepository.GetNCLevelSectionNames(sectionId, ProjectId);

            foreach (var scheGroup in groups)
            {
                var machine = validMachines.FirstOrDefault(q => q.section_id == scheGroup.Key.sectionId);
                if (machine == null)
                {
                    continue;
                }

                var reports = _reportRepository.GetList(q => q.machineid == machine.machine_id && q.projectid == ProjectId && q.status == (int) RowState.Valid).ToList();
                responses.Add(new ResponseGetMachineGante
                {
                    text = machine.lastSecondSectionTitle + "-" + machine.lastSectionTitle,
                    id = machine.machine_id + "_" + i
                });

                foreach (var machineGante in scheGroup.ToList())
                {
                    var codeOkNum = reports.Where(q => q.code == machineGante.orderNumber).Sum(q => q.actual_output);
                    var codeNokNum = reports.Where(q => q.code == machineGante.orderNumber).Sum(q => q.nok_number);

                    var data = new ResponseGetMachineGante
                    {
                        id = machineGante.id.ToString(),
                        parent = machine.machine_id + "_" + i,
                        text = machineGante.orderNumber,
                        machineName = machine.machine_name,
                        num = Math.Round((double)codeOkNum / machineGante.quanlity * 100 ,2),
                        start_date = UnixTimeHelper.ConvertIntDateTime(machineGante.startTime),
                        duration = UnixTimeHelper.ConvertStringDateTime(machineGante.endTime.ToString())
                            .Subtract(UnixTimeHelper.ConvertStringDateTime(machineGante.startTime.ToString())).TotalHours,
                        code = machineGante.code,
                        productName = machineGante.productName,
                        quanlity = machineGante.quanlity,
                        okNumber = codeOkNum,
                        nokNumber = codeNokNum
                    };

                    responses.Add(data);
                }

                i++;
            }
            return new ObjectResult(responses);
        }

        [HttpPost]
        public async Task<IActionResult> SaveMachineGante([FromBody]RequestSaveMachineGante request)
        {
            var entity = await _scheduleRepository.GetAsync(q => q.id == request.id && q.status == (int) RowState.Valid && q.projectId == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var startTime = UnixTimeHelper.GetUnixByShortDate(request.startTime);
            var endTime = UnixTimeHelper.GetUnixByShortDate(request.endTime);

            entity.startTime = startTime;
            entity.endTime = endTime;
            await _scheduleRepository.UpdateAsync(entity);
            if (await _unitOfWork.CommitAsync() > 0)
            {
                //修改计划结束时间和开始时间
                var planDetail = _planDetailRepository.Get(q => q.id == entity.plandetail_id && q.status == (int) RowState.Valid && q.projectId == ProjectId);
                if (planDetail != null)
                {
                    var schedules = _scheduleRepository.GetList(q =>
                        q.plandetail_id == entity.plandetail_id && q.status == (int) RowState.Valid && q.projectId == ProjectId).ToList();
                    planDetail.startTime = schedules.Min(q => q.startTime);
                    planDetail.endTime = schedules.Max(q => q.endTime);
                    _planDetailRepository.Update(planDetail);
                    _unitOfWork.Commit();
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }
    }
}