using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
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.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.Utility.ImportEntities;
using siger_project_product_plan = Siger.Middlelayer.CncRepository.Entities.siger_project_product_plan;

namespace Siger.Middlelayer.CncRepository.Repositories
{
    internal class ProductPlanRepository : CncRepositoryBase<Entities.siger_project_product_plan>, IProductPlanRepository
    {
        private readonly ApiCncDbContext _context;
        public ProductPlanRepository(ApiCncDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<ResponseGetProducesReport> GetPagedProductReport(string product_name, string draw_number, string code, IEnumerable<int> machinearr,
            int projectId, int startTime, int endTime, string ordernumber, string worker_name, string state, int page, int pagesize)
        {
            //var query = _context.siger_project_product_report.Where(q => q.projectid == projectId);
            var queryList = from a in _context.siger_project_product_report
                            join b in _context.siger_project_product_plan on a.plan_id equals b.id 
                            join s in _context.siger_project_level_section on a.station  equals s.id
                            join ss in _context.siger_project_level_section on s.parentid equals ss.id
                            join apu in _context.siger_project_user on a.approval_usermid equals apu.mid into aptemp
                            from user in aptemp.DefaultIfEmpty()
                            //from b in bb.DefaultIfEmpty()
                            where a.projectid == projectId
                            select new ResponseGetProducesReport
                            {
                                id = a.id,
                                plan_id = a.plan_id,
                                machineid = a.machineid,
                                code = a.code,
                                produced_program_number = a.produced_program_number,
                                start_time = a.start_time,
                                end_time = a.end_time,
                                actual_output = a.actual_output,
                                output = a.output,
                                time = a.time,
                                nok_number = a.nok_number,
                                worker_code = a.worker_code,
                                worker_name = a.worker_name,
                                draw_number = a.draw_number,
                                product_name = a.product_name,
                                product_code = a.product_code,
                                station = a.station,
                                orderNumber = b.code,//b != null ? b.code : a.code,
                                plan_type = 1,//b != null ? 2 : 1,
                                uid = a.uid,
                                approval_username = user!=null?user.name :"",
                                approval_time=a.approval_time,
                                route_name = a.route_name,
                                approval_usermid=a.approval_usermid,

                                rest_minutes = a.rest_minutes,
                                approval_status = Convert.ToInt32( a.approval_status),
                                machineLocation=ss.title+"-"+s.title
                            };
            var listItems = queryList.ToList();
            Expression<Func<ResponseGetProducesReport, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<ResponseGetProducesReport, bool>> drawNumberExpression = q => true;
            if (!string.IsNullOrEmpty(draw_number))
            {
                drawNumberExpression = q => q.draw_number.Contains(draw_number);
            }
            Expression<Func<ResponseGetProducesReport, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetProducesReport, bool>> midsExpression = q => true;
            if (machinearr.Any())
            {
                midsExpression = q => machinearr.Contains(q.machineid);
            }
            Expression<Func<ResponseGetProducesReport, bool>> startTimeExpression = q => true;
            if (startTime != 0 && endTime != 0)
            {
                startTimeExpression = q => q.time >= startTime && q.time <= endTime;
            }
            Expression<Func<ResponseGetProducesReport, bool>> ordernumberExpression = q => true;
            if (!string.IsNullOrWhiteSpace(ordernumber))
            {
                ordernumberExpression = q => q.code.Contains(ordernumber) || q.orderNumber.Contains(ordernumber);
            }
            Expression<Func<ResponseGetProducesReport, bool>> workcodeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(worker_name))
            {
                workcodeExpression = q => q.worker_name.Contains(worker_name); 
            }
            Expression<Func<ResponseGetProducesReport, bool>> stateExpression = q => true;
            if (!string.IsNullOrWhiteSpace(state))
            {
                int stateFinal = state.ToInt();
                stateExpression = q => q.approval_status == stateFinal;
            }

            var predicate = productNameExpression.And(drawNumberExpression).And(codeExpression).And(midsExpression)
                .And(startTimeExpression).And(ordernumberExpression).And(workcodeExpression).And(stateExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderByDescending(q => q.time)
                .Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
            return new PagedCollectionResult<ResponseGetProducesReport>(entities, totalCount);
        }
        public IPagedCollectionResult<ResponseGetProductPlan> GetPagedProductPlanOld(string product_name, string draw_number, string code, string ordernumber,
            string status,int ordertype, int startTime, int endTime, string isdelay, int projectId, int page, int pagesize)
        {
            var queryList = from q in _context.siger_project_product_plan
                            join p in _context.siger_project_product on q.product_id equals p.id
                            where q.projectid == projectId
                            select new ResponseGetProductPlan
                            {
                                product_id = q.product_id,
                                product_name = q.product_name,
                                product_code = q.product_code,
                                draw_number = q.draw_number,
                                product_remark = p.remark,
                                workordertype = q.workordertype,
                                partnumber = q.partnumber,
                                code = q.code,
                                ordernumber = q.ordernumber,
                                quantity = q.quantity,
                                delivery_time = q.delivery_time,
                                delivery_time_str = UnixTimeHelper.ConvertIntDate(q.delivery_time),
                                create_time = q.create_time,
                                create_time_str = UnixTimeHelper.ConvertIntDate(q.create_time),
                                status = q.status,
                                ok_number = q.producted_number,
                                nok_number = q.nok_number,
                                autogenerate = q.autogenerate,
                                source = q.source,
                                finish_time = q.finish_time,
                                id = q.id,
                                install_count = q.install_count
                            };
            Expression<Func<ResponseGetProductPlan, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<ResponseGetProductPlan, bool>> drawNumberExpression = q => true;
            if (!string.IsNullOrEmpty(draw_number))
            {
                drawNumberExpression = q => (q.draw_number.Contains(draw_number) || q.product_remark.Contains(draw_number));
            }
            Expression<Func<ResponseGetProductPlan, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetProductPlan, bool>> ordernumberExpression = q => true;
            if (!string.IsNullOrEmpty(ordernumber))
            {
                ordernumberExpression = q => q.ordernumber.Contains(ordernumber);
            }
            Expression<Func<ResponseGetProductPlan, bool>> statusExpression = q => true;
            if (!string.IsNullOrEmpty(status))
            {
                statusExpression = q => q.status == status.ToInt();
            }
           
            Expression<Func<ResponseGetProductPlan, bool>> delayExpression = q => true;
            if (!string.IsNullOrEmpty(isdelay))
            {
                var now = UnixTimeHelper.GetNow();
                if (isdelay.ToInt() == 1)
                {
                    delayExpression = q => q.status != 3 && q.delivery_time < now;
                }
                else
                {
                    delayExpression = q => q.delivery_time >= now;
                }
            }
            Expression<Func<ResponseGetProductPlan, bool>> startTimeExpression = q => true;
            if (startTime != 0 && endTime != 0)
            {
                startTimeExpression = q => q.create_time >= startTime && q.create_time <= endTime;
            }

            var predicate = productNameExpression.And(drawNumberExpression).And(codeExpression).And(ordernumberExpression).And(statusExpression)
                .And(delayExpression).And(startTimeExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderBy(q => q.status).ThenBy(q => q.delivery_time)
                .Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ResponseGetProductPlan>(entities, totalCount);
        }

        public IPagedCollectionResult<ResponseGetProductPlan> GetPagedProductPlan(string product_name, string draw_number, string code, string ordernumber,
           string status,int orderType,int startTime, int endTime, string isdelay, int projectId, int page, int pagesize)
        {
            var queryList = from q in _context.siger_project_product_plan
                            join p in _context.siger_project_product on q.product_id equals p.id
                            where q.projectid == projectId
                            select new ResponseGetProductPlan
                            {
                                product_id = q.product_id,
                                product_name = q.product_name,
                                product_code = q.product_code,
                                draw_number = q.draw_number,
                                product_remark = p.remark,
                                workordertype = q.workordertype,
                                partnumber = q.partnumber,
                                code = q.code,
                                ordernumber = q.ordernumber,
                                quantity = q.quantity,
                                delivery_time = q.delivery_time,
                                delivery_time_str = UnixTimeHelper.ConvertIntDate(q.delivery_time),
                                create_time = q.create_time,
                                create_time_str = UnixTimeHelper.ConvertIntDate(q.create_time),
                                status = q.status,
                                ok_number = q.producted_number,
                                nok_number = q.nok_number,
                                autogenerate = q.autogenerate,
                                source = q.source,
                                finish_time = q.finish_time,
                                id = q.id,
                                install_count = q.install_count
                            };
            Expression<Func<ResponseGetProductPlan, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<ResponseGetProductPlan, bool>> drawNumberExpression = q => true;
            if (!string.IsNullOrEmpty(draw_number))
            {
                drawNumberExpression = q => (q.draw_number.Contains(draw_number) || q.product_remark.Contains(draw_number));
            }
            Expression<Func<ResponseGetProductPlan, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetProductPlan, bool>> ordernumberExpression = q => true;
            if (!string.IsNullOrEmpty(ordernumber))
            {
                ordernumberExpression = q => q.ordernumber.Contains(ordernumber);
            }
            Expression<Func<ResponseGetProductPlan, bool>> statusExpression = q => true;
            if (!string.IsNullOrEmpty(status))
            {
                statusExpression = q => q.status == status.ToInt();
            }
            Expression<Func<ResponseGetProductPlan, bool>> ordertypeExpression = q => true;
            if (orderType != 0)
            {
                ordertypeExpression = q => q.workordertype == orderType;
            }

            Expression<Func<ResponseGetProductPlan, bool>> delayExpression = q => true;
            if (!string.IsNullOrEmpty(isdelay))
            {
                var now = UnixTimeHelper.GetNow();
                if (isdelay.ToInt() == 1)
                {
                    delayExpression = q => q.status != 3 && q.delivery_time < now;
                }
                else
                {
                    delayExpression = q => q.delivery_time >= now;
                }
            }
            Expression<Func<ResponseGetProductPlan, bool>> startTimeExpression = q => true;
            if (startTime != 0 && endTime != 0)
            {
                startTimeExpression = q => q.create_time >= startTime && q.create_time <= endTime;
            }

            var predicate = productNameExpression.And(drawNumberExpression).And(codeExpression).And(ordernumberExpression).And(statusExpression)
                .And(delayExpression).And(startTimeExpression).And(ordertypeExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderBy(q => q.status).ThenBy(q => q.delivery_time)
                .Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ResponseGetProductPlan>(entities, totalCount);
        }

        public IEnumerable<siger_project_product_plan> GetNoPagedProductPlan(string product_name, string draw_number, string code,
            string status, int projectId)
        {
            var queryList = _context.siger_project_product_plan.Where(q => q.projectid == projectId);
            Expression<Func<siger_project_product_plan, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<siger_project_product_plan, bool>> drawNumberExpression = q => true;
            if (!string.IsNullOrEmpty(draw_number))
            {
                drawNumberExpression = q => q.draw_number.Contains(draw_number);
            }
            Expression<Func<siger_project_product_plan, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<siger_project_product_plan, bool>> statusExpression = q => true;
            if (!string.IsNullOrEmpty(status))
            {
                statusExpression = q => q.status == status.ToInt();
            }

            var predicate = productNameExpression.And(drawNumberExpression).And(codeExpression).And(statusExpression);
            return queryList.Where(predicate).OrderBy(q => q.status).ThenBy(q => q.create_time).AsNoTracking().ToList();
        }

        public CommonImportResult ImportProducePlan(IEnumerable<ProducePlanList> plans, int projectId)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var productIds = new List<int>();
            foreach (var plan in plans)
            {
                rowIndex++;
                var entity = _context.siger_project_product_plan.FirstOrDefault(q => q.code == plan.Code && q.projectid == projectId);
                if (entity != null)
                {
                    errors.Add($"{rowIndex},{500141}");
                }
                if (plan.Quantity.ToInt() > 5000) // 限制订单数量
                {
                    errors.Add($"{rowIndex},{(int)CncEnum.PlanQuanlityOverFlow}");
                }

                var product = _context.siger_project_product.FirstOrDefault(q =>
                    q.drawingcode == plan.ProductDrawingCode && q.projectid == projectId
                                                             && q.status == (int)RowState.Valid);
                if (product == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ProductDrawingCodeNotFound}");
                }
                else
                {
                    productIds.Add(product.id);
                }
                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
            }

            try
            {
                var planEntities = plans.ToList();
                for (int i = 0; i < planEntities.Count; i++)
                {
                    var plan = planEntities[i];
                    var orderType = 1; //成品
                    if (plan.WorkOrderType == "半成品")
                    {
                        orderType = 2;
                    }
                    else if (plan.WorkOrderType == "返工")
                    {
                        orderType = 3;
                    }

                    string deliveryTime;
                    var date = plan.DeliveryTime.ToDouble();
                    if (date > 0)
                    {
                        deliveryTime = DateTime.FromOADate(date).ToString(ParameterConstant.DateToEnd);
                    }
                    else
                    {
                        var time = plan.DeliveryTime.ToDateTime();
                        deliveryTime = time == DateTime.MinValue
                            ? DateTime.Now.ToString(ParameterConstant.DateToEnd)
                            : plan.DeliveryTime.ToDateTime().ToString(ParameterConstant.DateToEnd);
                    }

                    var id = 0;
                    if (string.IsNullOrWhiteSpace(plan.Code))
                    {
                        id = _context.siger_project_product_plan.Max(q => q.id) + 1;
                    }
                    var planEntity = new siger_project_product_plan
                    {
                        code = string.IsNullOrWhiteSpace(plan.Code) ? DateTime.Now.ToString("yyyyMMdd") + "-" + id : plan.Code,
                        create_time = UnixTimeHelper.GetNow(),
                        delivery_time = UnixTimeHelper.GetUnixByShortDate(deliveryTime),
                        draw_number = plan.ProductDrawingCode,
                        product_id = productIds[i],
                        product_name = plan.ProductName,
                        producted_number = 0,
                        nok_number = 0,
                        quantity = plan.Quantity.ToInt(),
                        projectid = projectId,
                        product_code = plan.ProductCode,
                        partnumber = plan.PartNumber,
                        workordertype = orderType,
                        ordernumber = plan.OrderNumber,
                        source = (int)PlanSource.ExcelImport,
                        status = (int)PlanProcess.UnPlan,
                        install_count = plan.InstallCount.ToInt()
                    };
                    _context.siger_project_product_plan.Add(planEntity);
                }
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        public CommonImportResult ImportXuGongProducePlan(IEnumerable<ProducePlanList> plans, int projectId)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var productIds = new List<siger_project_product>();
            foreach (var plan in plans)
            {
                rowIndex++;
                var entity = _context.siger_project_product_plan.FirstOrDefault(q => q.code == plan.ProductCode && q.projectid == projectId);
                if (entity != null)
                {
                    errors.Add($"{rowIndex},{500141}");
                }
                if (plan.Quantity.ToInt() > 5000) // 限制订单数量
                {
                    errors.Add($"{rowIndex},{(int)CncEnum.PlanQuanlityOverFlow}");
                }

                var product = _context.siger_project_product.FirstOrDefault(q =>
                    q.code == plan.ProductCode && q.projectid == projectId
                                                             && q.status == (int)RowState.Valid);
                if (product == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ProductNotFound}");
                }
                else
                {
                    productIds.Add(product);
                }
                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
            }

            try
            {
                var planEntities = plans.ToList();
                for (int i = 0; i < planEntities.Count; i++)
                {
                    var plan = planEntities[i];
                    var orderType = 1; //成品
                    if (plan.WorkOrderType == "半成品")
                    {
                        orderType = 2;
                    }
                    else if (plan.WorkOrderType == "返工")
                    {
                        orderType = 3;
                    }

                    var planEntity = new siger_project_product_plan
                    {
                        code = plan.ProductCode,
                        create_time = UnixTimeHelper.GetNow(),
                        delivery_time = UnixTimeHelper.GetUnixByShortDate(plan.DeliveryTime + ParameterConstant.TimeToEnd),
                        draw_number = productIds[i].drawingcode,
                        product_id = productIds[i].id,
                        product_name = plan.ProductName,
                        producted_number = 0,
                        nok_number = 0,
                        quantity = plan.Quantity.ToInt(),
                        projectid = projectId,
                        product_code = plan.ProductCode,
                        partnumber = plan.PartNumber,
                        workordertype = orderType,
                        ordernumber = plan.OrderNumber,
                        source = (int)PlanSource.ExcelImport,
                        status = (int)PlanProcess.UnPlan
                    };
                    _context.siger_project_product_plan.Add(planEntity);
                }
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        public IEnumerable<ResponseAllPassProductReport> GetAllPassProductReports(int sectionId, long startDate, long endDate, string ordernumber, int userId, int projectId,int approve)
        {
            var mids = GetLevelSectionIds(sectionId, projectId);
            var query = from q in _context.siger_project_product_report
                        //join m in _context.siger_project_machine on q.machineid equals m.id
                        join l in _context.siger_project_level_section on q.station equals l.id
                        join p in _context.siger_project_product_plan on q.plan_id equals p.id
                        join pd in _context.siger_project_product_plan_detail on p.id  equals pd.planId
                        join u in _context.siger_project_user on q.uid equals u.mid
                        join r in _context.siger_project_product_route on q.route_id equals r.id
                        where q.projectid==projectId 
                        && q.status == (int)RowState.Valid 
                        select new ResponseAllPassProductReport
                        {
                            id=q.id,
                            code = p.code,
                            ordernumber = p.ordernumber,
                            drawcode=p.draw_number,
                            gonglingdan = q.code,
                            machineId = q.station,
                            machineTitle=l.title,
                            actual_output = q.actual_output,
                            ngcount=q.nok_number,
                            product_id = p.product_id,
                            product_name = p.product_name,
                            worker_code = u.work_code,
                            worker_name = u.name,
                            user_mid = u.mid,
                            working_hour = r.working_hours,
                            prepare = r.prepare,
                            time=q.time,
                            route_id=q.route_id,
                            route_name=q.route_name,
                            approval_status=q.approval_status== OrderReportApprovalStatus.Pass?1:0
                        };
            //Expression<Func<ResponseAllPassProductReport, bool>> sectionExpression = f => true;
            //if (sectionId != 0)
            //{
            //    var machineIds = GetLevelSectionMachineIds(sectionId, projectId);
            //    sectionExpression = q => machineIds.Contains(q.machineId);
            //}
            Expression<Func<ResponseAllPassProductReport, bool>> approveExpression = f => true;
            if (approve!=0)
            {
                approveExpression = q => q.approval_status == approve;
            }
            Expression<Func<ResponseAllPassProductReport, bool>> timeExpression = f => true;
            if (startDate !=0 && endDate!=0)
            {
                timeExpression = q => q.time >= startDate && q.time <= endDate;
            }
            Expression<Func<ResponseAllPassProductReport, bool>> codeExpression = f => true;
            if (!string.IsNullOrWhiteSpace(ordernumber))
            {
                codeExpression = q => q.ordernumber == ordernumber;
            }
            Expression<Func<ResponseAllPassProductReport, bool>> userExpression = f => true;
            if (userId != 0)
            {
                userExpression = q => q.user_mid == userId;
            }
            Expression<Func<ResponseAllPassProductReport, bool>> midsExpression = f => true;
            if (mids.Any())
            {
                midsExpression = q => mids.Contains(q.machineId);
            }
            var predicate = approveExpression.And(timeExpression).And(codeExpression).And(userExpression).And(midsExpression);
            return query.Where(predicate).GroupBy(g => g.id).Select(f => f.FirstOrDefault()).ToList();
        }
        /// <summary>
        /// 查时间内所有报工
        /// </summary>
        /// <param name="sectionId">产线层级</param>
        /// <param name="startDate">时间范围--开始</param>
        /// <param name="endDate">时间范围--结束</param>
        /// <param name="projectId">项目id</param>
        /// <returns></returns>
        public IEnumerable<QualificationRate> GetAllPassProductReports(int sectionId, long startDate, long endDate, int projectId)
        {
         
            var sections = GetLevelSectionIds(sectionId, projectId);
            var query = from rp in _context.siger_project_product_report
                        join rt in _context.siger_project_product_route on rp.route_id equals rt.id
                        //join pc in _context.siger_project_machine_attribution on rp.machineid equals pc.machine
                        join oc in _context.siger_project_level_section on rp.station equals oc.id
                        join ss in _context.siger_project_level_section on oc.parentid equals ss.id
                        join u in _context.siger_project_user on rp.uid equals u.mid
                        where rp.projectid == projectId 
                        && rp.status == (int)RowState.Valid  && rt.status==(int)RowState.Valid
                        && rp.time >= startDate && rp.time <= endDate
                        && sections.Contains(rp.station)
                        select new QualificationRate
                        {
                            actual_output=rp.actual_output,
                            report_id = rp.id,
                            station_id = rp.station,
                            station_name = oc.title,
                            uid=u.mid,
                            worker_code = u.work_code,
                            worker_name = u.name,
                            product_name = rp.product_name,
                            route_name = rp.route_name,
                            machinelocal= ss.title+'-'+oc.title,
                            code=rp.code,
                            nok_number=rp.nok_number,
                            time=rp.time,
                            machineid = rp.machineid,
                            day=UnixTimeHelper.ConvertStringDateTime(rp.time.ToStr()).Day
                        };

            return query;
        }
        #region 生产计划管理
        /// <summary>
        /// 生产计划管理
        /// </summary>
        /// <param name="product_name">产品名称</param>
        /// <param name="draw_number">图纸号</param>
        /// <param name="code">工单号</param>
        /// <param name="ordernumber">订单号</param>
        /// <param name="status">订单状态</param>
        /// <param name="startTime">添加时间--开始</param>
        /// <param name="endTime">添加时间--结束</param>
        /// <param name="isdelay">是否延期</param>
        /// <param name="projectId"></param>
        /// <param name="page"></param>
        /// <param name="pagesize"></param>
        /// <returns></returns>
        public IPagedCollectionResult<ResponseGetProductPlanManage> GetPagedProductPlanManage(string product_name, string draw_number, string code, string ordernumber,
           int status, int startTime, int endTime, int isdelay, int projectId,int delayStart,int delayEnd, int page, int pagesize)
        {
            var queryList = from q in _context.siger_project_product_plan
                            where q.projectid == projectId
                            select new ResponseGetProductPlanManage
                            {
                                
                                product_id = q.product_id,
                                ordernumber = q.ordernumber,
                                code = q.code,
                                install_count=q.install_count,
                                product_name = q.product_name,
                                product_code = q.product_code,
                                workordertype = q.workordertype,
                                quantity = q.quantity,
                                producted_number = q.producted_number,
                                create_time = q.create_time,
                                create_time_str = UnixTimeHelper.ConvertIntDate(q.create_time),
                                delivery_time = q.delivery_time,
                                delivery_time_str = UnixTimeHelper.ConvertIntDate(q.delivery_time),
                                draw_number = q.draw_number,
                                status = q.status, // fq.workorder_status == null ? 1 : fq.workorder_status.ToInt(),
                                autogenerate = q.autogenerate,
                                source = q.source,
                                id = q.id,
                            };
            Expression<Func<ResponseGetProductPlanManage, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> drawNumberExpression = q => true;
            if (!string.IsNullOrEmpty(draw_number))
            {
                drawNumberExpression = q => (q.draw_number.Contains(draw_number));
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> ordernumberExpression = q => true;
            if (!string.IsNullOrEmpty(ordernumber))
            {
                ordernumberExpression = q => q.ordernumber.Contains(ordernumber);
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> statusExpression = q => true;
            if (status!=0)
            {
                statusExpression = q => q.status == status;
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> delayExpression = q => true;
            if (isdelay!=0)
            {
                var now = UnixTimeHelper.GetNow();
                if (isdelay == 1)//延期
                {
                    delayExpression = q => q.status != 5 && q.delivery_time < now;
                }
                else//未延期
                {
                    delayExpression = q => q.delivery_time >= now;
                }
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> startTimeExpression = q => true;
            if (startTime != 0 && endTime != 0)
            {
                startTimeExpression = q => q.create_time >= startTime && q.create_time <= endTime;
            }
            Expression<Func<ResponseGetProductPlanManage, bool>> delayTimeExpression = q => true;
            if (delayStart != 0 && delayEnd != 0)
            {
                delayTimeExpression = q => q.delivery_time >= delayStart && q.delivery_time <= delayEnd;
            }

            var predicate = productNameExpression.And(drawNumberExpression).And(codeExpression).And(ordernumberExpression).And(statusExpression)
                .And(delayExpression).And(startTimeExpression).And(delayTimeExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderBy(q=>q.status).OrderByDescending(q => q.create_time).ThenBy(q => q.delivery_time)
                .Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ResponseGetProductPlanManage>(entities, totalCount);
        }

        /// <summary>
        /// 生产计划管理导入
        /// </summary>
        /// <param name="plans"></param>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public CommonImportResult ImportProductionPlan(IEnumerable<ProductionPlanList> plans, int projectId)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var productIds = new List<int>();
            var planEntities = new List<ProductionPlanList>();
            bool same = plans.GroupBy(i => i).Where(g => g.Count() > 1).Count() >0;
            //bool code = plans.GroupBy(i => i.Code).Where(g => g.Count() > 1).Count() >= 1;
            if(same)//导入数据不能重复
            {
                errors.Add($"{((int)CncEnum.DataToSame)}");
            }

            foreach (var plan in plans)
            {
                rowIndex++;
                var entity = _context.siger_project_product_plan.FirstOrDefault(q => q.code == plan.Code && q.projectid == projectId);
                if (entity != null)
                {
                    errors.Add($"{rowIndex},{500141}");
                }
                if (plan.Quantity.ToInt() > 5000) // 限制订单数量
                {
                    errors.Add($"{rowIndex},{(int)CncEnum.PlanQuanlityOverFlow}");
                }
                if(string.IsNullOrEmpty(plan.OrderNumber))//订单号不能为空
                {
                    errors.Add($"{rowIndex},{(int)CncEnum.OrderNumberNotNull}");
                }
                if(string.IsNullOrEmpty(plan.WorkOrderType))//工单类型不能为空
                {
                    errors.Add($"{ rowIndex},{(int)CncEnum.WorkOrderTypeNotNull}");
                }

                var product = _context.siger_project_product.FirstOrDefault(q =>
                    q.drawingcode == plan.ProductDrawingCode && q.projectid == projectId
                                                             && q.status == (int)RowState.Valid);
                if (product == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ProductDrawingCodeNotFound}");
                }
                else
                {
                    productIds.Add(product.id);
                }
                if (planEntities.Exists(s=>s.Code==plan.Code))
                {
                    errors.Add($"{ rowIndex},{(int)CncEnum.DataToSame}");
                }
                if (planEntities.Exists(s => s.OrderNumber == plan.OrderNumber))
                {
                    errors.Add($"{ rowIndex},{(int)CncEnum.DataToSame}");
                }
                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
                planEntities.Add(plan);
            }

            try
            {
              //  var planEntities = plans.ToList();

                var index = 0;
                var planCode = _context.siger_project_product_plan
                    .Where(d => UnixTimeHelper.ConvertIntDate(d.create_time) == DateTime.Now.ToString("yyyy-MM-dd") && d.source == 2 && d.projectid == projectId)
                    .OrderBy(i => i.id).ToList();
                if (!planCode.Any())
                {
                    index = 0;
                }
                else
                {
                    index = Regex.Split(planCode.Last().code, "00", RegexOptions.IgnoreCase).Last().ToInt();
                }

                for (int i = 0; i < planEntities.Count; i++)
                {
                    var plan = planEntities[i];
                    var orderType = 1; //成品
                    if (plan.WorkOrderType == "新品")
                    {
                        orderType = 2;
                    }
                    else if (plan.WorkOrderType == "调试")
                    {
                        orderType = 3;
                    }
                    else if (plan.WorkOrderType == "返工")
                    {
                        orderType = 4;
                    }

                    string deliveryTime;
                    var date = plan.DeliveryTime.ToDouble();
                    if (date > 0)
                    {
                        deliveryTime = DateTime.FromOADate(date).ToString(ParameterConstant.DateToEnd);
                    }
                    else
                    {
                        var time = plan.DeliveryTime.ToDateTime();
                        deliveryTime = time == DateTime.MinValue
                            ? DateTime.Now.ToString(ParameterConstant.DateToEnd)
                            : plan.DeliveryTime.ToDateTime().ToString(ParameterConstant.DateToEnd);
                    }

                    var id = 0;
                    if (string.IsNullOrWhiteSpace(plan.Code))
                    {
                        id = _context.siger_project_product_plan.Max(q => q.id) + 1;
                    }
                    var planEntity = new siger_project_product_plan
                    {
                        code = string.IsNullOrWhiteSpace(plan.Code) ? plan.OrderNumber + "-" + DateTime.Now.ToString("MMdd") + "00" + (index + i + 1) : plan.Code,
                        create_time = UnixTimeHelper.GetNow(),
                        delivery_time = UnixTimeHelper.GetUnixByShortDate(deliveryTime),
                        draw_number = plan.ProductDrawingCode,
                        product_id = productIds[i],
                        product_name = plan.ProductName,
                        quantity = plan.Quantity.ToInt(),
                        projectid = projectId,
                        product_code = plan.ProductCode,
                        workordertype = orderType,
                        ordernumber = plan.OrderNumber,
                        source = (int)PlanSource.ExcelImport,
                        status = (int)PlanDispatch.UnIssue,
                        //装机数量改为工单数量
                        install_count = plan.InstallCount.ToInt()
                    };
                    _context.siger_project_product_plan.Add(planEntity);
                }
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        #endregion

        /// <summary>
        /// 查时间内所有工单信息
        /// </summary>
        /// <param name="sectionid">产线层级</param>
        /// <param name="productid">产品名称id</param>
        /// <param name="starttime">时间范围--开始</param>
        /// <param name="endtime">时间范围--结束</param>
        /// <param name="projectId">项目id</param>
        /// <param name="page">第几页</param>
        /// <param name="pagesize">每页条数</param>
        /// <returns></returns>
        public IPagedCollectionResult<ResponsePlanExecutionAnalysis> GetAllPlanDetails(int sectionid, int productid, int starttime, int endtime, int projectId,
            int page, int pagesize)
        {
            var query = from sp in _context.siger_project_product_plan
                        join sr in _context.siger_project_product_report on sp.id equals sr.plan_id
                        where
                        sp.projectid == projectId
                        && sp.status == (int)RowState.Valid &&  sr.status == (int)RowState.Valid
                        && sp.create_time >= starttime && sp.create_time <= endtime                       
                        select new ResponsePlanExecutionAnalysis
                        {
                            id = sp.id,
                            code = sp.code,
                            product_id = sp.product_id,
                            product_name = sp.product_name,
                            plan_number = sp.quantity,
                            actual_number = sr.actual_output + sr.nok_number,
                            delivery_time = sp.delivery_time,
                            ok_number = sr.actual_output,
                            nok_number = sr.nok_number,

                        };
            Expression<Func<ResponsePlanExecutionAnalysis, bool>> sectionExpression = f => true;
            if (sectionid != 0)
            {
                var machineIds = GetLevelSectionMachineIds(sectionid, projectId);
                sectionExpression = q => machineIds.Contains(q.machineid);
            }
            Expression<Func<ResponsePlanExecutionAnalysis, bool>> productidExpression = f => true;
            if (productid != 0)
            {
                productidExpression = q => q.product_id == productid;
            }

            var predicate = sectionExpression.And(productidExpression);
            var data = query.Where(predicate).ToList().GroupBy(c => new { c.id, c.code, c.product_id, c.product_name, c.plan_number, c.delivery_time })
                .Select(
                            c => new ResponsePlanExecutionAnalysis
                            {
                                id = c.Key.id,
                                code = c.Key.code,
                                product_id=c.Key.product_id,
                                product_name = c.Key.product_name,
                                plan_number = c.Key.plan_number,
                                delivery_time = c.Key.delivery_time,
                                actual_number = c.Sum(x => x.actual_number),
                                ok_number = c.Sum(x => x.ok_number),
                                nok_number = c.Sum(x => x.nok_number),
                                pass_rate= Math.Round(c.Sum(x => x.ok_number).ToStr().ToDouble()/(c.Sum(x => x.ok_number) + c.Sum(x => x.nok_number))*100,
                                2).FormatDouble()
                            }
                         );
            var responData =data.Skip((page - 1) * pagesize).Take(pagesize).ToList();
            var plannumber = data.Sum(f=>f.plan_number);
            var actualnumber = data.Sum(f=>f.actual_number);
            
            return new PagedCollectionResult<ResponsePlanExecutionAnalysis>(responData, data.Count());
        }
        /// <summary>
        /// 查时间内所有工单数量汇总
        /// </summary>
        /// <param name="sectionid">产线层级</param>
        /// <param name="productid">产品名称id</param>
        /// <param name="starttime">时间范围--开始</param>
        /// <param name="endtime">时间范围--结束</param>
        /// <param name="projectId">项目id</param>
        /// <returns></returns>
        public ResponsePlanSum GetAllPlanSum(int sectionid, int productid, int starttime, int endtime, int projectId)
        {
            var query = from p in _context.siger_project_product_plan
                        join pd in _context.siger_project_product_plan_detail on p.id equals pd.planId
                        join r in _context.siger_project_product_report on pd.orderNumber equals r.code
                        where p.projectid == projectId && r.plan_id== pd.planId
                        && p.create_time >= starttime && p.create_time <= endtime
                        select new ResponsePlanExecutionAnalysis
                        {
                            id = p.id,
                            code = p.code,
                            product_id = p.product_id,
                            product_name = p.product_name,
                            plan_number = p.install_count,
                            actual_number = p.producted_number + p.nok_number,
                            delivery_time = p.delivery_time,
                            ok_number =pd.ok_number,
                            nok_number = pd.nok_number,
                            actual_completiontime=p.finish_time

                        };
            Expression<Func<ResponsePlanExecutionAnalysis, bool>> sectionExpression = f => true;
            if (sectionid != 0)
            {
                var machineIds = GetLevelSectionMachineIds(sectionid, projectId);
                sectionExpression = q => machineIds.Contains(q.machineid);
            }
            Expression<Func<ResponsePlanExecutionAnalysis, bool>> productidExpression = f => true;
            if (productid != 0)
            {
                productidExpression = q => q.product_id == productid;
            }

            var predicate = sectionExpression.And(productidExpression);
            var data = query.Where(predicate).ToList().GroupBy(c => new { c.id, c.code, c.product_id, c.product_name, c.plan_number, c.delivery_time,c.actual_completiontime })
                .Select(
                            c => new ResponsePlanExecutionAnalysis
                            {
                                id = c.Key.id,
                                code = c.Key.code,
                                product_id = c.Key.product_id,
                                product_name = c.Key.product_name,
                                plan_number = c.Key.plan_number,
                                delivery_time = c.Key.delivery_time,
                                actual_completiontime=c.Key.actual_completiontime,
                                actual_number = c.Sum(x => x.actual_number),
                                ok_number = c.Sum(x => x.ok_number),
                                nok_number = c.Sum(x => x.nok_number),
                                pass_rate = Math.Round(c.Sum(x => x.ok_number).ToStr().ToDouble() / (c.Sum(x => x.ok_number) + c.Sum(x => x.nok_number)) * 100,
                                2).FormatDouble()
                            }
                         );
            var entity = new ResponsePlanSum();
            entity.plannumber = data.Sum(f => f.plan_number);
            entity.actualnumber = data.Sum(f => f.actual_number);
            entity.total = data.Count();

            var oknumber= data.Sum(f => f.ok_number);
            var planin=data.Where(f=>f.actual_completiontime>0&&f.actual_completiontime<=f.delivery_time).Sum(f => f.actual_number);

            entity.productpercent = Math.Round((entity.actualnumber.ToStr().ToDouble() / entity.plannumber)*100,2);
            entity.planpercent = Math.Round(planin.ToStr().ToDouble()/ entity.plannumber,2);
            entity.qualitypercent = Math.Round((oknumber.ToStr().ToDouble()/entity.plannumber), 2);

            return entity;
        }

        #region 手机app报工 获取人员报工信息
        /// <summary>
        /// 获取人员报工信息
        /// </summary>
        /// <param name="userid">人员mid</param>
        /// <param name="projectId">项目id</param>
        /// <returns></returns>
        public ResponseUserReport GetReportDetails(int userid, int projectId)
        {
            siger_project_user user = null;
            if (userid != 0)
            {
                user = _context.siger_project_user.FirstOrDefault(q => q.mid == userid && q.projectid == projectId && q.status == (int)RowState.Valid);
                if (user == null)
                {
                    return new ResponseUserReport();
                }
            }

            var query = from q in _context.siger_project_product_report
                        join p in _context.siger_project_product_plan on q.plan_id equals p.id
                        join u in _context.siger_project_user on q.worker_code equals u.work_code
                        join sr in _context.siger_project_product_route on p.product_id equals sr.productId
                        where u.mid == userid && q.status == (int)RowState.Valid && q.projectid == projectId
                        select new ResponseUserReportDetails
                        {
                            ok_number = q.actual_output,
                            nok_number=q.nok_number,
                            product_name = p.product_name,
                            route_name = sr.name,
                            report_time = UnixTimeHelper.ConvertIntYmd(q.time)+" "+ UnixTimeHelper.ConvertIntHm(q.time),
                        };
            var data = new ResponseUserReport();
            if (query!=null)
            {
                data.oksum = query.Sum(f => f.ok_number);
                data.noksum = query.Sum(f => f.nok_number);
                data.data = query.ToList();
            }
            return data;
        }




        #endregion

        public IPagedCollectionResult<ResponseGetProductNoPlan> GetPagedProductNoPlan(string product_name, string code, string startTime, string endTime,
            int projectId, int page, int pagesize)
        {
            var queryList = from q in _context.siger_project_product_plan_detail
                            join s in _context.siger_project_produce_schedule on q.id equals s.plandetail_id
                            join p in _context.siger_project_product on q.levelId equals p.id
                            join l in _context.siger_project_machine_attribution on s.sectionId equals l.station
                            join m in _context.siger_project_machine on l.machine equals m.id
                            join u1 in _context.siger_project_user on q.operator_mid equals u1.mid
                            join u2 in _context.siger_project_user on q.creator_mid equals u2.mid
                            where q.projectId == projectId && q.planId == 0
                            select new ResponseGetProductNoPlan
                            {
                                id = q.id,
                                product_id = q.levelId,
                                product_name = p.name,
                                product_code = p.code,
                                draw_number = p.drawingcode,
                                code = q.orderNumber,
                                create_time = q.addTime,
                                quantity = q.quantity,
                                route_name = s.route_name,
                                operator_name = u1.name,
                                add_name = u2.name,
                                machine_name = m.title,
                                status = q.status,
                                working_hours = s.working_hours.ToStr(),
                                prepare = s.prepare.ToStr(),
                                remark = q.remark
                            };
            Expression<Func<ResponseGetProductNoPlan, bool>> productNameExpression = q => true;
            if (!string.IsNullOrEmpty(product_name))
            {
                productNameExpression = q => q.product_name.Contains(product_name);
            }
            Expression<Func<ResponseGetProductNoPlan, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetProductNoPlan, bool>> startTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(startTime))
            {
                startTimeExpression = q => q.create_time >= DateTime.Parse(startTime);
            }
            Expression<Func<ResponseGetProductNoPlan, bool>> endTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(endTime))
            {
                endTimeExpression = q => q.create_time <= DateTime.Parse(endTime).AddDays(1);
            }

            var predicate = productNameExpression.And(codeExpression).And(startTimeExpression).And(endTimeExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderByDescending(q => q.create_time).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ResponseGetProductNoPlan>(entities, totalCount);
        }
    }
}
