using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.CncRepository.Entities;
using Siger.Middlelayer.CncRepository.Repositories.Interface;
using Siger.Middlelayer.CncRepository.Response;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.FieldEnum;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Repository.Response;

namespace Siger.Middlelayer.CncRepository.Repositories
{
    internal class ProductPlanDetailRepository : CncRepositoryBase<siger_project_product_plan_detail>, IProductPlanDetailRepository
    {

        private readonly ApiCncDbContext _context;
        public ProductPlanDetailRepository(ApiCncDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<ResponseGetOrders> GetPagedWorkOrderList(string productName, string code, string orderNumber, int status,
            string startTime, string endTime, int projectId, int page, int pagesize)
        {
            var reports = (from r in _context.siger_project_product_report
                join d in _context.siger_project_product_plan_detail on r.code equals d.orderNumber
                select r.code).Distinct().ToList();

            var queryList = from q in _context.siger_project_product_plan_detail
                join p in _context.siger_project_product_plan on q.planId equals p.id
                join r in reports on q.orderNumber equals r into rr
                from re in rr.DefaultIfEmpty()
                where q.projectId == projectId && q.status == (int)RowState.Valid && p.status != (int)PlanProcess.Stop
                select new ResponseGetOrders
                {
                    id = q.id,
                    code = p.code,
                    delivery_time = p.delivery_time,
                    orderNumber = q.orderNumber,
                    product_name = p.product_name,
                    product_id = p.product_id,
                    producted_number = q.ok_number,
                    quantity = q.quantity,
                    //status = q.ok_number == 0 ? 1 : (q.ok_number - q.quantity) >= 0 ? 3 : 2,
                    status = re == null ? 1 : (q.ok_number - q.quantity) >= 0 ? 3 : 2,
                    difference = q.quantity - q.ok_number,
                    addTime = q.addTime,
                    levelId = q.levelId,
                    product_code = p.product_code
                };

            Expression<Func<ResponseGetOrders, bool>> productNameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(productName))
            {
                productNameExpression = q => q.product_name.Contains(productName);
            }
            Expression<Func<ResponseGetOrders, bool>> codeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetOrders, bool>> orderNumberExpression = q => true;
            if (!string.IsNullOrWhiteSpace(orderNumber))
            {
                orderNumberExpression = q => q.orderNumber.Contains(orderNumber);
            }
            Expression<Func<ResponseGetOrders, bool>> statusExpression = q => true;
            if (status > 0)
            {
                statusExpression = q => q.status == status;
            }
            Expression<Func<ResponseGetOrders, bool>> startTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(startTime))
            {
                var dtStart = DateTime.Parse(startTime);
                startTimeExpression = q => q.addTime >= dtStart;
            }
            Expression<Func<ResponseGetOrders, bool>> endTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(endTime))
            {
                var dtEnd = DateTime.Parse(endTime).AddDays(1);
                endTimeExpression = q => q.addTime < dtEnd;
            }

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

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

            var result = new List<ResponseGetOrders>();
            foreach (var orderse in entities)
            {
                var routes = string.Empty;
                var allRouteIds = new List<int>();
                var query = from q in _context.siger_project_product_route
                    where q.productId == orderse.product_id && q.projectId == projectId && q.status == (int)RowState.Valid
                    select q;
                if (query.Any())
                {
                    routes = string.Join("-", query.OrderBy(q => q.serialNumber).ToList().Select(m => m.name));
                    allRouteIds = query.OrderBy(q => q.serialNumber).ToList().Select(m => m.id).ToList();
                }
                orderse.routes = routes;
                orderse.route_ids = allRouteIds;

                //取最大的工序号
                var routeIds = _context.siger_project_product_report.Where(q => q.code == orderse.orderNumber && q.projectid == projectId &&  q.status == (int) RowState.Valid)
                                                                        .Select(m => m.route_name).Distinct().ToList();

                var maxSerialNumber = _context.siger_project_product_route
                    .Where(q => routeIds.Contains(q.id.ToString()) && q.projectId == projectId && q.status == (int) RowState.Valid).OrderByDescending(q => q.serialNumber)
                    .Select(m => m.serialNumber).FirstOrDefault();
                if (maxSerialNumber > 0)
                {
                    orderse.report_routes = string.Join("-", _context.siger_project_product_route
                        .Where(q => q.productId == orderse.product_id && q.projectId == projectId && q.status == (int) RowState.Valid && q.serialNumber <= maxSerialNumber)
                        .OrderBy(o => o.serialNumber).Select(m => m.name).ToList());

                    var route = _context.siger_project_product_route
                        .FirstOrDefault(q => q.productId == orderse.product_id && q.projectId == projectId
                                                                               && q.status == (int) RowState.Valid &&
                                                                               q.serialNumber == maxSerialNumber);
                    if (route != null)
                    {
                        orderse.report_routeId = route.id;
                    }
                }

                result.Add(orderse);
            }

            result = result.OrderBy(q => q.status).ThenBy(q => q.delivery_time).ToList();

            return new PagedCollectionResult<ResponseGetOrders>(result, totalCount);
        }

        #region 工令单任务一览
        /// <summary>
        /// 工令单一览
        /// </summary>
        /// <param name="productName">产品名称</param>
        /// <param name="code">工单号</param>
        /// <param name="orderNumber">订单号</param>
        /// <param name="status">工单状态</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<ResponseGetOrders> GetPagedWorkOrderListData(string productName, string code, string orderNumber, int status,
            string startTime, string endTime, int projectId, int page, int pagesize)
        {

            var queryList = from q in _context.siger_project_product_plan_detail
                            join p in _context.siger_project_product_plan on q.planId equals p.id
                            where q.projectId == projectId 
                            select new ResponseGetOrders
                            {
                                id = q.id,
                                planId=q.planId,
                                //工令号
                                orderNumber = q.orderNumber,
                                delivery_time = p.delivery_time,
                                product_name = p.product_name,
                                product_code = p.product_code,
                                ok_number=q.ok_number,
                                nok_number=q.nok_number,
                                code = p.code,
                                status = p.delivery_time <= UnixTimeHelper.ConvertDataTimeLong(DateTime.Now.ToString())&& q.status!=(int)PlanDispatch.Finished?(int)PlanDispatch.Overdue: q.status,
                                quantity = q.quantity,
                                producted_number = q.producted_number,
                                difference = q.quantity - q.producted_number,
                                product_id = p.product_id,
                                addTime = q.addTime,
                                levelId = q.levelId,                               
                            };

            Expression<Func<ResponseGetOrders, bool>> productNameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(productName))
            {
                productNameExpression = q => q.product_name.Contains(productName);
            }
            Expression<Func<ResponseGetOrders, bool>> codeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseGetOrders, bool>> orderNumberExpression = q => true;
            if (!string.IsNullOrWhiteSpace(orderNumber))
            {
                orderNumberExpression = q => q.orderNumber.Contains(orderNumber);
            }
            Expression<Func<ResponseGetOrders, bool>> statusExpression = q => true;
            if (status > 0)
            {
                statusExpression = q => q.status == status;
            }
            Expression<Func<ResponseGetOrders, bool>> startTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(startTime))
            {
                var dtStart = DateTime.Parse(startTime);
                startTimeExpression = q => q.addTime >= dtStart;
            }
            Expression<Func<ResponseGetOrders, bool>> endTimeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(endTime))
            {
                var dtEnd = DateTime.Parse(endTime).AddDays(1);
                endTimeExpression = q => q.addTime < dtEnd;
            }

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

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

           var result = entities.OrderBy(q => q.status).ThenBy(q => q.delivery_time).ToList();

            return new PagedCollectionResult<ResponseGetOrders>(result, totalCount);
        }

        /// <summary>
        /// 打印工单获取弹框数据
        /// </summary>
        /// <param name="id">工令号数据id</param>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public IEnumerable<ResponseWorkOrderList> GetWorkOrderData(int id,int projectId)
        {
            var data = from sd in _context.siger_project_product_plan_detail
                       join sp in _context.siger_project_product_plan on sd.planId equals sp.id
                       join sr in _context.siger_project_product_route on sp.product_id equals sr.productId
                       join u in _context.siger_project_user on sd.creator_mid equals u.mid
                       where sd.id == id && sd.projectId == projectId &&
                       sr.status == (int)RowState.Valid
                       select new ResponseWorkOrderList
                       {
                           ordernumber = sp.ordernumber,
                           delivery_time = UnixTimeHelper.ConvertIntDate(sp.delivery_time),
                           code =sp.code,
                           addTime =sd.addTime,
                           product_name =sp.product_name,
                           orderNumber =sd.orderNumber,
                           route_id=sr.id,
                           serialNumber =sr.serialNumber,
                           name =sr.name,
                           description =sr.description,
                           quantity =sd.quantity,
                           ok_number =sd.ok_number,
                           nok_number =sd.nok_number,
                           product_code =sp.product_code,
                           user=u.name
                       };

            return data.OrderBy(O=>O.serialNumber);
        }


        #endregion


        public IEnumerable<ResponseIdTitle> GetSectionTitles(IEnumerable<int> sectionIds, int projectId)
        {
            var sections = _context.siger_project_level_section.Where(q =>
                sectionIds.Contains(q.id) && q.projectid == projectId && q.status == (int) RowState.Valid).ToList();

            var responses = new List<ResponseIdTitle>();
            foreach (var section in sections)
            {
                responses.Add(new ResponseIdTitle
                {
                    id = section.id,
                    title = section.title
                });
            }

            return responses;
        }

        public IPagedCollectionResult<ResponseGetOrders> GetPlanExecuteList(int startTime, int endTime,
            int productId, int projectId, int page, int pagesize, int toexcel)
        {
            var queryList = from p in _context.siger_project_product_plan
                            where p.projectid == projectId && p.status != (int)PlanProcess.Stop
                            select new ResponseGetOrders
                            {
                                id = p.id,
                                code = p.code,
                                orderNumber = p.ordernumber,
                                partnumber = p.partnumber,
                                delivery_time = p.delivery_time,
                                product_name = p.product_name,
                                product_id = p.product_id,
                                producted_number = p.producted_number + p.nok_number,
                                quantity = p.quantity,
                                ok_number = p.producted_number,
                                nok_number = p.nok_number,
                                status = p.status
                            };

            Expression<Func<ResponseGetOrders, bool>> productNameExpression = q => true;
            if (productId !=0)
            {
                productNameExpression = q => q.product_id == productId;
            }
            Expression<Func<ResponseGetOrders, bool>> startTimeExpression = q => q.delivery_time >= startTime;
            Expression<Func<ResponseGetOrders, bool>> endTimeExpression = q => q.delivery_time <= endTime;

            var predicate = productNameExpression.And(startTimeExpression).And(endTimeExpression);
            var totalCount = queryList.Count(predicate);

            List<ResponseGetOrders> entities = null;

            if (toexcel == 0)
            {
                entities = queryList.Where(predicate).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
            }
            else
            {
                entities = queryList.Where(predicate).AsNoTracking().ToList();
            }

            var result = new List<ResponseGetOrders>();
            foreach (var orderse in entities)
            {
                var dateTime = UnixTimeHelper.ConvertStringDateTime(orderse.delivery_time.ToString());
                orderse.difference = dateTime.Subtract(DateTime.Now).Days;

                var total = orderse.ok_number + orderse.nok_number;
                orderse.rate = total == 0 ? 0 : Math.Round(orderse.ok_number / decimal.Parse(total.ToString()) * 100, 2);
                result.Add(orderse);
            }

            result = result.OrderBy(q => q.orderNumber).ThenBy(q => q.delivery_time).ToList();
            return new PagedCollectionResult<ResponseGetOrders>(result, totalCount);
        }

        public IEnumerable<ResponseWorkOrderGante> GetWorkOrderGante(string productName, string draw_number, string code, int status, 
            int startTime, int endTime, int projectId)
        {
            var queryList = from q in _context.siger_project_product_plan
                where q.projectid == projectId && (q.status != (int) PlanProcess.Stop && q.status != (int)PlanProcess.UnPlan)
                select new ResponseWorkOrderGante
                {
                    id = q.id,
                    draw_number = q.draw_number,
                    code = q.code,
                    delivery_time = q.delivery_time,
                    productName = q.product_name,
                    quantity = q.quantity,
                    ok_number = q.producted_number,
                    nok_number = q.nok_number,
                    actEndTime = q.finish_time,
                    isDelay = q.finish_time > q.delivery_time ? 1 : 0,
                    status = q.status,
                    addTime = q.create_time
                };

            Expression<Func<ResponseWorkOrderGante, bool>> productNameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(productName))
            {
                productNameExpression = q => q.productName.Contains(productName);
            }
            Expression<Func<ResponseWorkOrderGante, bool>> drawNnumberExpression = q => true;
            if (!string.IsNullOrWhiteSpace(draw_number))
            {
                drawNnumberExpression = q => q.draw_number.Contains(draw_number);
            }
            Expression<Func<ResponseWorkOrderGante, bool>> codeExpression = q => true;
            if (!string.IsNullOrWhiteSpace(code))
            {
                codeExpression = q => q.code.Contains(code);
            }
            Expression<Func<ResponseWorkOrderGante, bool>> statusExpression = q => true;
            if (status != 0)
            {
                statusExpression = q => q.status == status;
            }

            Expression<Func<ResponseWorkOrderGante, bool>> startTimeExpression = q => true;
            if (startTime != 0)
            {
                startTimeExpression = q => q.addTime >= startTime;
            }

            Expression<Func<ResponseWorkOrderGante, bool>> endTimeExpression = q => true;
            if (endTime != 0)
            {
                endTimeExpression = q => q.addTime <= endTime;
            }

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

            return queryList.Where(predicate).AsNoTracking().ToList();
        }

        public IEnumerable<ResponseGetOrders> GetSignPlans(int startTime, int endTime, IEnumerable<int> planIds, int projectId)
        {
            var queryList = from p in _context.siger_project_product_plan_detail
                join plan in _context.siger_project_product_plan on p.planId equals plan.id 
                            where p.projectId == projectId
                            select new ResponseGetOrders
                            {
                                id = plan.id,
                                code = plan.code,
                                orderNumber = p.orderNumber,
                                delivery_time = plan.delivery_time,
                                product_name = plan.product_name,
                                product_code = plan.product_code,
                                product_id = plan.product_id,
                                producted_number = p.ok_number + p.nok_number,
                                quantity = p.quantity,
                                ok_number = p.ok_number,
                                nok_number = p.nok_number,
                                status = p.ok_number == 0 ? 1 : (p.ok_number - p.quantity) >= 0 ? 3 : 2,
                                levelId = p.levelId,
                                StartTime = p.startTime,
                                EndTime = p.endTime
                            };

            Expression<Func<ResponseGetOrders, bool>> planIdsExpression = q => true;
            if (planIds.Any())
            {
                planIdsExpression = q => planIds.Contains(q.id);
            }

            Expression<Func<ResponseGetOrders, bool>> timeExpression = q => true;
            if (startTime > 0 && endTime > 0)
            {
                timeExpression = q => q.StartTime <= endTime && q.StartTime >= startTime || q.EndTime <= endTime && q.EndTime >= startTime;
            }

            var predicate = planIdsExpression.And(timeExpression);

            var entities = queryList.Where(predicate).AsNoTracking().ToList();

            entities = entities.OrderBy(q => q.orderNumber).ThenBy(q => q.delivery_time).ToList();

            var result = new List<ResponseGetOrders>();
            foreach (var orderse in entities)
            {
                var routes = string.Empty;
                var query = from q in _context.siger_project_product_route
                    join s in _context.siger_project_level_section on q.sectionId equals s.id
                    where q.levelId == orderse.levelId && q.productId == orderse.product_id
                                                       && q.projectId == projectId && q.status == (int)RowState.Valid
                    select s;
                if (query.Any())
                {
                    routes = string.Join("-", query.ToList().Select(m => m.title));
                }
                orderse.routes = routes;

                if (orderse.status == 1) //查看是否有报工
                {
                    var reports = _context.siger_project_product_report.Where(q => q.code == orderse.orderNumber
                                                                                   && q.projectid == projectId && q.status == (int)RowState.Valid).Sum(m => m.actual_output);
                    if (reports > 0)
                    {
                        orderse.status = 2;
                    }
                }

                result.Add(orderse);
            }
            return result;
        }

        public IEnumerable<ResponseGetOrders> GetWorkOrderProgress(string productName, string orderNumber, 
            DateTime startTime, DateTime endTime, int projectId)
        {
            var queryList = from q in _context.siger_project_product_plan
                            where q.projectid == projectId && q.status != (int)PlanProcess.Stop
                            select new ResponseGetOrders
                            {
                                id = q.id,
                                code = q.code,
                                orderNumber = q.ordernumber,
                                product_name = q.product_name,
                                product_id = q.product_id,
                                producted_number = q.producted_number,
                                quantity = q.quantity,
                                addTime = UnixTimeHelper.ConvertStringDateTime(q.create_time.ToString())
                            };

            Expression<Func<ResponseGetOrders, bool>> productNameExpression = q => true;
            if (!string.IsNullOrWhiteSpace(productName))
            {
                productNameExpression = q => q.product_name.Contains(productName);
            }
            Expression<Func<ResponseGetOrders, bool>> orderNumberExpression = q => true;
            if (!string.IsNullOrWhiteSpace(orderNumber))
            {
                orderNumberExpression = q => q.orderNumber.Contains(orderNumber);
            }
            Expression<Func<ResponseGetOrders, bool>> startTimeExpression = q => q.addTime >= startTime;
            Expression<Func<ResponseGetOrders, bool>> endTimeExpression = q => q.addTime < endTime;

            var predicate = productNameExpression.And(orderNumberExpression).And(startTimeExpression).And(endTimeExpression);
            var entities = queryList.Where(predicate).OrderByDescending(q => q.delivery_time).AsNoTracking().ToList();

            return entities;
        }
        /// <summary>
        /// 获取排产工令单信息 （电子票据）
        /// </summary>
        /// <param name="wo"></param>
        /// <param name="projeceId"></param>
        /// <returns></returns>
        public ScheduleWoInfo GetWoSchedule(string wo, int projeceId)
        {
            var query = from d in _context.siger_project_product_plan_detail
                        join p in _context.siger_project_product_plan on d.planId equals p.id
                        join s in _context.siger_project_produce_schedule on d.id equals s.plandetail_id
                        join l in _context.siger_project_level_section on s.sectionId equals l.id
                        join u in _context.siger_project_user on d.operator_mid equals u.mid into temp
                        from t in temp.DefaultIfEmpty()
                        join r in _context.siger_project_product_route on s.route_name equals r.name 
                        where d.projectId == projeceId && d.orderNumber == wo && p.product_id ==r.productId &&
                        d.status == (int)RowState.Valid &&
                        s.status==(int)RowState.Valid && 
                        r.status==(int)RowState.Valid
                        select new ScheduleWoInfo
                        {
                            Id=d.id,
                            WO = d.orderNumber,
                            ProductId = p.product_code,
                            ProductName = p.product_name,
                            Quantity = d.quantity,
                            OrderNumber=d.orderNumber,
                            PlanId=p.id,
                            SectionId = l.id,
                            SectionName = l.title,
                            PlanTime=UnixTimeHelper.ConvertIntDateTime(s.startTime),
                            Uid = d.operator_mid,
                            ProductRoute=r.id,
                            ProductRouteDesc=r.name,
                            Uname = t == null ? d.operator_mid.ToString() : t.name

                        };
            return query.FirstOrDefault();
        }

        /// <summary>
        /// 获取除暂停的工令单 报工明细
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="planId"></param>
        /// <param name="planDtsId"></param>
        /// <returns></returns>
        public IEnumerable<ResponsePlanReportDetails> GetPlanReports(int projectId, int planId,int planDtsId)
        {
            var query = from pd in _context.siger_project_product_plan_detail
                        join p in _context.siger_project_product_plan on pd.planId equals p.id
                        join route in _context.siger_project_product_route on p.product_id equals route.productId
                        where pd.projectId == projectId && pd.status != (int)PlanDispatch.Stop && route.status==(int)RowState.Valid
                        select new ResponsePlanReportDetails
                        {
                             code=pd.orderNumber,
                             plan_id=pd.planId,
                             plandDts_id=pd.id,
                             status = p.delivery_time <= UnixTimeHelper.ConvertDataTimeLong(DateTime.Now.ToString()) && p.status!=(int)PlanDispatch.Finished ? (int)PlanDispatch.Overdue : p.status,
                             quantity=pd.quantity,
                             order_cnt=p.quantity,
                             order_installCnt=p.install_count,
                             route_id=route.id,
                             route_name=route.name,
                             route_serinum=route.serialNumber
                        };
            Expression<Func<ResponsePlanReportDetails, bool>> planidExpression = q => true;
            if (planId!=0)
            {
                planidExpression = q => q.plan_id==planId;
            }
            Expression<Func<ResponsePlanReportDetails, bool>> planDtsidExpression = q => true;
            if (planDtsId != 0)
            {
                planDtsidExpression = q => q.plandDts_id == planDtsId;
            }
            var predicate = planidExpression.And(planDtsidExpression);
            return  query.Where(predicate);
        }

        public string GetDrawUrl(int productId, int projectId)
        {
            var url = from a in _context.siger_project_esop_document
                      join b in _context.siger_project_esop_document_history on a.id equals b.document_id
                      where a.project_id == projectId && a.status == (int)RowState.Valid && b.default_display == 1 && a.product_id==productId && a.approval_status == DocumentApprovalStatus.ApprovalPass
                      select b;
            if (url.Any())
            {
                return url.FirstOrDefault().file_url;
            }
            else
            {
                return null;
            } 
        }
    }
}
