using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.AccRepository.Entities;
using Siger.Middlelayer.AccRepository.Repositories.Interface;
using Siger.Middlelayer.AccRepository.Response;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Repository.Data.Acc;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using System.Threading.Tasks;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository.Entities;

namespace Siger.Middlelayer.AccRepository.Repositories
{
    internal class SigerTrSnTraceRepository : AccRepositoryBase<SigerTrSnTrace>, ISigerTrSnTraceRepository
    {
        private readonly ApiAccDbContext accDbContext;
        public SigerTrSnTraceRepository(ApiAccDbContext context) : base(context)
        {
            accDbContext = context;
        }
        /// <summary>
        /// 良率 统计
        /// </summary>
        /// <param name="productid"></param>
        /// <param name="line"></param>
        /// <param name="starttime"></param>
        /// <param name="endtime"></param>
        /// <param name="projectid"></param>
        /// <returns></returns>
        public IEnumerable<ResponseSnTrace> GetCountList(string productid, int line, string starttime, string endtime, int projectid)
        {

            Expression<Func<SigerTrSnTrace, bool>> Funcat = f => f.projectId == projectid && f.status == (int)RowState.Valid;
            Expression<Func<SigerTrSnTrace, bool>> FunProductId = f => true;
            Expression<Func<SigerTrSnTrace, bool>> FunLine = f => true;
            Expression<Func<SigerTrSnTrace, bool>> FunTransStartTime = f => true;
            Expression<Func<SigerTrSnTrace, bool>> FunTransEndTime = f => true;
            if (!string.IsNullOrEmpty(productid) && productid != "0")
                FunProductId = f => f.ProductID == productid;
            if (line > 0)
                FunLine = f => f.Line == line;
            if (!string.IsNullOrEmpty(starttime) && !string.IsNullOrEmpty(endtime))
                FunTransStartTime = f => (f.TransDateTime >= starttime.ToDateTime() && f.TransDateTime <= endtime.ToDateTime());

            var predicate = Funcat.And(FunProductId).And(FunLine).And(FunTransStartTime).And(FunTransEndTime);

            var queryResult = from d in accDbContext.siger_tr_sn_trace.Where(predicate)
                              join l in accDbContext.siger_project_level_section on d.Line equals l.id
                              join s in accDbContext.siger_project_level_section on d.Station equals s.id
                              select new ResponseSNRptStation
                              {
                                  Sn = d.SN,
                                  SeqID = d.SeqID,
                                  Line = l.title,
                                  LineSetion = d.Line,
                                  Station = s.title,
                                  StationSection = d.Station,
                                  Result = d.Result,
                                  ProductID = d.ProductID
                              };

            var groupData = queryResult.GroupBy(g => new { g.Line, g.LineSetion, g.Station, g.StationSection, g.ProductID }).Select(s => new ResponseSnTrace
            {
                line = s.Key.LineSetion,
                line_value = s.Key.Line,
                station = s.Key.StationSection,
                station_value = s.Key.Station,
                productid = s.Key.ProductID,
                productid_value = s.Key.ProductID,
                total = s.Count(),
                yeild = Math.Round(s.Count(f => f.Result.ToUpper().Equals("OK")) / Convert.ToDecimal(s.Count()), 4),
                okcol = s.Count(f => f.Result.ToUpper().Equals("OK")),
                nocol = s.Count(f => !f.Result.ToUpper().Equals("OK"))
            });

            return groupData;

        }

        public IPagedCollectionResult<SNTraceInfo> GetTrSNTracePagedList(IEnumerable<int> stations, string productID, string sn, DateTime startTime, DateTime endTime, string pn, string result)
        {
            Expression<Func<SNTraceInfo, bool>> FunSn = f => true;
            Expression<Func<SNTraceInfo, bool>> FunTime = f => true;
            Expression<Func<SNTraceInfo, bool>> FunPn = f => true;
            Expression<Func<SNTraceInfo, bool>> FunResult = f => true;
            Expression<Func<SNTraceInfo, bool>> FunProduct = f => true;

            var query = from s in accDbContext.siger_tr_sn_trace
                        join q in accDbContext.siger_tr_sn_list on s.Line equals q.Line
                        where s.SN == q.SN && stations.Contains(s.Station)
                        select new SNTraceInfo
                        {
                            SeqID = s.SeqID,
                            SN = s.SN,
                            ProductID = s.ProductID,
                            Line = s.Line,
                            WO = s.WO,
                            Station = s.Station,
                            Position = s.Position,
                            UID = s.UID,
                            Result = s.Result,
                            TransDateTime = s.TransDateTime,
                            LastUpdateTime = s.LastUpdateTime,
                            PN = q.PN,
                        };
            if (!string.IsNullOrEmpty(sn))
            {
                FunSn = q => q.SN.Contains(sn);
            }
            else
            {
                FunTime = q => q.LastUpdateTime > startTime && q.LastUpdateTime < endTime;

            }
            if (!string.IsNullOrEmpty(pn))
            {
                FunPn = q => q.PN == pn;
            }
            if (!string.IsNullOrEmpty(result))
            {
                FunResult = q => q.Result == result;
            }
            if (!string.IsNullOrEmpty(productID))
            {
                FunProduct = q => q.ProductID == productID;
            }
            var predicate = FunSn.And(FunTime).And(FunResult).And(FunPn).And(FunProduct);
            var totalCount = query.Count(predicate);
            var entities = query.Where(predicate).OrderByDescending(q => q.LastUpdateTime).AsNoTracking().ToList();
            return new PagedCollectionResult<SNTraceInfo>(entities, totalCount);
        }

        public async Task<IPagedCollectionResult<ResponseSNRptStation>> TrSNTraceDateRtpPagedList(string sn, DateTime begin, DateTime end, int projectId, string productId, int line, int station, string pn, int page = 1, int pagesize = 10, EvenNoEnum evenNo = EvenNoEnum.Default)
        {
            return await Task.Run(() =>
            {
                Expression<Func<SigerTrSnTrace, bool>> FunSn = f => true;
                Expression<Func<SigerTrSnTrace, bool>> FunDate = f => true;
                Expression<Func<SigerTrSnTrace, bool>> FunProduct = f => true;
                Expression<Func<SigerTrSnTrace, bool>> FunLine = f => true;
                Expression<Func<SigerTrSnTrace, bool>> FunStation = f => true;
                Expression<Func<SigerTrSnTrace, bool>> FunEvenNo = f => true;
                //  Expression<Func<ResponseSNRptStation, bool>> FunPn = f => true;
                if (!string.IsNullOrEmpty(sn))
                    FunSn = f => f.SN.Contains(sn) && f.projectId == projectId;//TODO projectId多余
                else
                    FunDate = f => f.TransDateTime >= begin && f.TransDateTime <= end && f.projectId == projectId;

                if (!string.IsNullOrEmpty(productId))
                    FunProduct = f => f.ProductID.Contains(productId);
                if (line != 0)
                    FunLine = f => f.Line == line;
                if (station != 0)
                    FunStation = f => f.Station == station;
                if (evenNo != EvenNoEnum.Default)
                {
                    FunEvenNo = f => f.Result.ToUpper() == evenNo.ToStr();
                }
                var predicate = FunSn.And(FunDate).And(FunProduct).And(FunLine).And(FunStation).And(FunEvenNo);

                var queryResult = from d in accDbContext.siger_tr_sn_trace.Where(predicate)
                                  join l in accDbContext.siger_project_level_section on d.Station equals l.id 
                                  join h in accDbContext.siger_project_level_section on l.parentid equals h.id
                                  join s in accDbContext.siger_project_level_section on d.Station equals s.id
                                  join u in accDbContext.siger_project_user on d.UID equals u.mid into temp                                  
                                  from usr in temp.DefaultIfEmpty()
                                  join q in accDbContext.siger_project_product on d.ProductID equals q.code into qq
                                  from q in qq.DefaultIfEmpty()
                                  join r in accDbContext.siger_project_product_route on d.ProductRoute equals r.id into rtemp
                                  from proute in rtemp.DefaultIfEmpty()
                                  select new ResponseSNRptStation
                                  {
                                      Id=d.id,
                                      Sn = d.SN,
                                      SeqID = d.SeqID,
                                      LineSetion = h.id,
                                      Line = h.title,
                                      StationSection = d.Station,
                                      Station = s.title,
                                      Result = d.Result,
                                      ProductID = q!=null? q.code :"",
                                      WO = d.WO ?? "",
                                      Uid = d.UID,
                                      TransDateTime = d.TransDateTime,
                                      UpdateDateTime = d.LastUpdateTime,
                                      User = usr == null ? d.UID.ToString() : usr.name,
                                      productdraw=q!=null?q.drawingcode:"",
                                      productname=q!=null?q.name:"",
                                      ProductRoute=proute==null?"":proute.name
                                  };
                var totalCount = queryResult.Count();
                var result = queryResult.OrderByDescending(o=>o.Id).Skip((page - 1) * pagesize).Take(pagesize).OrderBy(o => o.Line).ThenBy(o => o.Station).ThenByDescending(q => q.TransDateTime).AsNoTracking();
                return new PagedCollectionResult<ResponseSNRptStation>(result, totalCount);
            });
        }
        /// <summary>
        /// 服务于导出Trace
        /// </summary>
        /// <param name="sns"></param>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public async Task<List<ResponseSNRptStation>> TrSNTraceDateRtpPagedList(List<string> sns, int projectId)
        {
            return await Task.Run(() =>
            {
                var ret = new List<ResponseSNRptStation>();
                if (!sns.Any())
                    return ret;
                var queryResult = from d in accDbContext.siger_tr_sn_trace.Where(f => sns.Contains(f.SN) && f.projectId == projectId && f.status == (int)RowState.Valid)
                                  join l in accDbContext.siger_project_level_section on d.Line equals l.id
                                  join s in accDbContext.siger_project_level_section on d.Station equals s.id
                                  join u in accDbContext.siger_project_user on d.UID equals u.mid into temp
                                  from usr in temp.DefaultIfEmpty()
                                  select new ResponseSNRptStation
                                  {

                                      Sn = d.SN,
                                      SeqID = d.SeqID,
                                      LineSetion = d.Line,
                                      Line = l.title,
                                      StationSection = d.Station,
                                      Station = s.title,
                                      Result = d.Result,
                                      ProductID = d.ProductID ?? "",
                                      WO = d.WO ?? "",
                                      Uid = d.UID,
                                      TransDateTime = d.TransDateTime,
                                      UpdateDateTime = d.LastUpdateTime,
                                      User = usr == null ? d.UID.ToString() : usr.name
                                  };
                return queryResult.OrderBy(o => o.Line).ThenBy(o => o.Station).ThenByDescending(q => q.TransDateTime).AsNoTracking().ToList();
            });
        }
        public async Task<IEnumerable<SnTraceInfo>> GetSnData(List<string> snlist)
        {
            return await Task.Run(() =>
            {
                var query = from t in accDbContext.siger_tr_sn_trace
                            where snlist.Contains(t.SN)
                            join u in accDbContext.siger_project_user on t.UID equals u.mid
                            into utemp
                            from usr in utemp.DefaultIfEmpty()
                            select new SnTraceInfo
                            {
                                Section = t.Station,
                                SeqId = t.SeqID,
                                Sn = t.SN,
                                User = usr == null ? t.UID.ToStr() : usr.name,
                                Result = t.Result,
                                Time = t.TransDateTime.ToStr()
                            };
                return query.ToList();
            });
        }

        public async Task<IPagedCollectionResult<SigerTrSnList>> GetRework(Expression<Func<SigerTrSnList, bool>> FunCond, int page, int pagesize)
        {
            return await Task.Run(() =>
            {
                var query = from s in accDbContext.siger_tr_sn_list.Where(FunCond)
                            join t in accDbContext.siger_tr_rework_sn_list on s.SN equals t.SN
                            where s.Line == t.Line
                            select new SigerTrSnList
                            {
                                SN = s.SN,
                                id = s.id,
                                Line = s.Line,
                                PN = s.PN,
                                ProductCode = s.ProductCode,
                                InputDateTime = s.InputDateTime,
                                TransDateTime = s.TransDateTime,
                                WO = s.WO,
                                ResultStatus = s.ResultStatus,
                                status = s.status,
                                projectId = s.projectId

                            };
                var rework = query.Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
                var totalCount = query.Count();
                return new PagedCollectionResult<SigerTrSnList>(rework, totalCount);
            });
        }

        public bool SaveCncReport(siger_project_product_report entity)
        {
            accDbContext.siger_project_product_report.Add(entity);
            return accDbContext.SaveChanges() > 0;
        }

        public bool UpdCncReport(siger_project_product_report entity)
        {
            accDbContext.siger_project_product_report.Update(entity);
            return accDbContext.SaveChanges() > 0;
        }

        /// <summary>
        /// SKF 追溯
        /// </summary>
        /// <param name="sn"></param>
        /// <param name="staions"></param>
        /// <param name="paramss"></param>
        /// <param name="projectId"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public IPagedCollectionResult<ResponseTrSnObj> GetTrTracePagedList(string sn, List<int> staions,
            List<string> paramss, int projectId, DateTime begin, DateTime end, int page, int pageSize)
        {
            Expression<Func<ResponseTrSnObj, bool>> funSn = f => true;
            Expression<Func<ResponseTrSnObj, bool>> funDate = f => true;
            Expression<Func<ResponseTrSnObj, bool>> funParam = f => true;

            var query = from b in accDbContext.siger_tr_sn_trace
                join d in accDbContext.siger_tr_sn_trace_detail on b.SeqID equals d.SeqID into traceTemp
                from dts in traceTemp.DefaultIfEmpty()
                join u in accDbContext.siger_project_user on b.UID equals u.mid into temp
                from us in temp.DefaultIfEmpty()
                where b.projectId == projectId && staions.Contains(b.Station)
                select new ResponseTrSnObj
                {
                    SeqID = b.SeqID,
                    Sn = b.SN,
                    Section = b.Station,
                    Busidate = b.LastUpdateTime,
                    ProductCode = b.ProductID,
                    Result = b.Result,
                    User = us != null ? us.name : "",
                    Item = dts != null ? dts.Item : ""
                };

            //Sn 不为空时 与时间无关
            if (!string.IsNullOrEmpty(sn))
                funSn = q => q.Sn.Contains(sn);
            else
                funDate = q => q.Busidate >= begin && q.Busidate <= end;

            if (paramss.Any())
            {
                var itemMap = accDbContext.siger_tr_parameter_config
                    .Where(f => f.projectId == projectId && paramss.Contains(f.attribute)).Select(s => s.name).ToList();
                funParam = q => itemMap.Contains(q.Item);
            }

            var predicate = funSn.And(funDate).And(funParam);
            var list = query.Where(predicate).GroupBy(g => g.SeqID).Select(s => s.FirstOrDefault());
            var entities = list.OrderByDescending(d=>d.Busidate).Skip((page - 1) * pageSize).Take(pageSize).AsNoTracking().ToList();
            var totalCount = list.Count();
            return new PagedCollectionResult<ResponseTrSnObj>(entities, totalCount);
        }
    }
}
