using System;
using System.Collections.Generic;
using System.Linq;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.WmsRepository.Entities;
using Siger.Middlelayer.WmsRepository.Repositories.Interface;
using Siger.Middlelayer.WmsRepository.Response;

namespace Siger.Middlelayer.WmsRepository.Repositories
{
    internal class siger_wms_stocktake_orderRepository : WMSRepositoryBase<siger_wms_stocktake_order>, Isiger_wms_stocktake_orderRepository
    {
        private readonly ApiWmsDbContext dbContext;
        public siger_wms_stocktake_orderRepository(ApiWmsDbContext context) : base(context)
        {
            dbContext = context;
        }

        public IEnumerable<ResponseWaveHousing> GetBills(CheckStatu type, int projectId, int page, int pageSize, out int totalCount)
        {
            var start = DateTime.Now.AddDays(-DateTime.Now.Day + 1);
            IQueryable<siger_wms_stocktake_order> data;
            switch (type)
            {
                case CheckStatu.Waitting:
                case CheckStatu.Checked:
                case CheckStatu.Checking:
                case CheckStatu.Finish:
                case CheckStatu.Canceled:
                case CheckStatu.Failed:
                    //根据状态过滤
                    data = GetList(f => f.projectid == projectId && f.status == (int)RowState.Valid && f.update_time >= start.Date && f.update_time <= DateTime.Now);
                    break;
                default:
                    data = GetList(f => f.projectid == projectId && f.update_time >= start.Date && f.update_time <= DateTime.Now);
                    break;
            }
            totalCount = data.Count();
            data = data.Skip((page - 1) * pageSize).Take(pageSize);

            var result = (from info in data
                          join user in dbContext.siger_user on info.updator equals user.id into userData
                          from userInfo in userData.DefaultIfEmpty()
                          join storage in dbContext.siger_wms_storage on info.storageid equals storage.id into re
                          from r in re.DefaultIfEmpty()
                          select new ResponseWaveHousing
                          {
                              id = info.id,
                              name = userInfo.nickname,
                              order_number = info.order_number,
                              storageName = r.name,
                              time = info.update_time
                          }).ToList();
            //汇总数据
            var orderids = data.Select(f => f.id).ToList();
            var details = dbContext.siger_wms_stocktake_order_detail.Where(f => orderids.Contains(f.orderid) && f.status == (int)RowState.Valid && f.projectid == projectId).GroupBy(f => f.orderid).ToList();
            var detailsDic = details.ToDictionary(f => f.First().order_number, f => f.Count());

            foreach (var item in result)
            {
                if (detailsDic.Any(f => f.Key == item.order_number))
                {
                    item.count = detailsDic[item.order_number];
                }
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="waveHouseID"></param>
        /// <param name="stocks"></param>
        /// <param name="projectId"></param>
        /// <param name="userId"></param>
        /// <param name="billcode"></param>
        public void AddCheckBill(int waveHouseID, List<int> stocks, int projectId, int userId,string billcode)
        {
            //检测是否为同一个仓库
            var stockData = dbContext.siger_wms_stock.Where(f => f.projectid == projectId && f.status == (int)RowState.Valid && stocks.Contains(f.id));
            if (stockData.Count() != stocks.Count())
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            var locationids = dbContext.siger_wms_storage_location.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.storageid == waveHouseID).Select(f => f.id).ToList();

            //存在不属于此仓库的库存记录
            if (stockData.Count(f => !locationids.Contains(f.storage_location_id)) > 0)
            {
                throw new BadRequestException(RequestEnum.StorageLocationNotMatch);
            }

            //添加单据表头
            var order = new siger_wms_stocktake_order
            {
                order_number = billcode,
                order_status = (int)CheckStatu.Waitting,
                projectid = projectId,
                status = (int)RowState.Valid,
                storageid = waveHouseID,
                create_time = DateTime.Now,
                creator = userId,
                update_time = DateTime.Now,
                updator = userId
            };
            Insert(order);
            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }

            //添加详情
            foreach (var item in stockData)
            {
                var tmp = new siger_wms_stocktake_order_detail
                {
                    stockid = item.id,
                    orderid = order.id,
                    material_id = item.material_id,
                    material_name = item.material_name,
                    material_pn = item.material_pn,
                    material_spec = item.material_spec,
                    quantity = item.quantity,
                    stocktaked_quantity = 0,
                    order_number = billcode,
                    create_time = DateTime.Now,
                    creator = userId,
                    update_time = DateTime.Now,
                    updator = userId,
                    projectid = projectId,
                    status = (int)RowState.Valid,
                    stocktake_status = (int)CheckStatu.Waitting,
                    businessid=item.businessid,
                    businessName=GetBusinessName(item.businessid,projectId)
                };
                dbContext.siger_wms_stocktake_order_detail.Add(tmp);
            }

            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id">盘点单id</param>
        /// <param name="stockids">库存id</param>
        /// <param name="projectId"></param>
        /// <param name="userId"></param>
        public void UpdateBill(int id, List<int> stockids, int projectId, int userId)
        {
            var order = Get(f => f.status == (int)RowState.Valid && f.id == id);
            var existData = dbContext.siger_wms_stocktake_order_detail.Where(f => f.orderid == id && f.status == (int)RowState.Valid && f.projectid == projectId).ToList();

            //删除不需要的数据
            var allid = existData.Select(f => f.stockid).ToList();
            var needDel = allid.Except(stockids);
            var needDelData = existData.Where(f => needDel.Contains(f.stockid)).ToList();
            needDelData.ForEach(f =>
            {
                f.status = (int)RowState.Invalid;
            });
            dbContext.siger_wms_stocktake_order_detail.UpdateRange(needDelData);

            existData = existData.Where(f => !needDel.Contains(f.stockid)).ToList();

            //更新需要的数据的信息
            foreach (var item in existData)
            {
                item.update_time = DateTime.Now;
                item.updator = userId;
            }
            dbContext.siger_wms_stocktake_order_detail.UpdateRange(existData);

            //创建新数据
            var existIDs = existData.Select(f => f.stockid).ToList();
            var newIDs = stockids.Except(existIDs);

            //检测库存是否存在
            var stockData = dbContext.siger_wms_stock.Where(f => f.projectid == projectId && f.status == (int)RowState.Valid && newIDs.Contains(f.id));
            if (stockData.Count() != newIDs.Count())
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            //检测是否为同一个仓库
            var locationids = dbContext.siger_wms_storage_location.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.storageid == order.storageid).Select(f => f.id).ToList();

            //存在不属于此仓库的库存记录
            if (stockData.Count(f => !locationids.Contains(f.storage_location_id)) > 0)
            {
                throw new BadRequestException(RequestEnum.StorageLocationNotMatch);
            }
            //添加详情
            foreach (var item in stockData)
            {
                var tmp = new siger_wms_stocktake_order_detail
                {
                    stockid = item.id,
                    orderid = order.id,
                    material_id = item.material_id,
                    material_name = item.material_name,
                    material_pn = item.material_pn,
                    material_spec = item.material_spec,
                    quantity = item.quantity,
                    stocktaked_quantity = 0,
                    order_number = order.order_number,
                    create_time = DateTime.Now,
                    creator = userId,
                    update_time = DateTime.Now,
                    updator = userId,
                    projectid = projectId,
                    status = (int)RowState.Valid,
                    stocktake_status = (int)CheckStatu.Checking
                };
                dbContext.siger_wms_stocktake_order_detail.Add(tmp);
            }
            order.update_time = DateTime.Now;
            order.updator = userId;
            Update(order);

            if (dbContext.SaveChanges() <= 0)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        public IEnumerable<ResponseGetBillList> GetBillList(int storageid, CheckStatu type, string sn, int page, int pageSize, out int totalCount, int projectId, int userId, CheckedStatu filter = CheckedStatu.No, bool isExport = false, DateTime? start = null, DateTime? end = null)
        {
            var data = GetList(f => f.status == (int)RowState.Valid && f.projectid == projectId);

            if (0 != storageid)
            {
                data = data.Where(f => f.storageid == storageid);
            }
            switch (type)
            {
                case CheckStatu.Waitting:
                case CheckStatu.Checked:
                case CheckStatu.Checking:
                case CheckStatu.Finish:
                case CheckStatu.Canceled:
                case CheckStatu.Failed:
                    data = data.Where(f => f.order_status == (int)type);
                    break;
                default:
                    break;
            }
            if (!string.IsNullOrEmpty(sn))
            {
                data = data.Where(f => f.order_number == sn.Trim());
            }

            if (filter != CheckedStatu.No)
            {
                if (start != null)
                {
                    data = data.Where(f => f.update_time >= start);
                }
                if (end != null)
                {
                    data = data.Where(f => f.update_time <= end);
                }
            }


            totalCount = data.Count();


            var result = (from info in data
                          join wavehouse in dbContext.siger_wms_storage on info.storageid equals wavehouse.id
                          into tmp1
                          from wavehouseInfo in tmp1.DefaultIfEmpty()
                          join creater in dbContext.siger_user on info.creator equals creater.id into tmp2
                          from createrData in tmp2.DefaultIfEmpty()
                          join checker in dbContext.siger_user on info.auditor equals checker.id into resultData
                          from r in resultData.DefaultIfEmpty()
                          select new ResponseGetBillList
                          {
                              id = info.id,
                              order_number = info.order_number,
                              creatername = createrData.nickname,
                              create_time = info.create_time,
                              auditname = r.nickname,
                              audittime = info.audit_time == DateTime.MinValue || info.audit_time == null ? "" : info.audit_time.ToString(UnixTimeHelper.DateTimeFormat),
                              order_status = info.order_status,
                              order_statusName = "",
                              storageid = info.storageid,
                              storagename = wavehouseInfo.name
                          }).ToList();

            //transform 盘盈 盘亏
            var more = EnumHelper.GetEnumDesc(CheckedStatu.MORE);
            var less = EnumHelper.GetEnumDesc(CheckedStatu.LESS);


            foreach (var item in result)
            {
                if (item.order_status != (int)CheckStatu.Finish)
                {
                    item.order_statusName = EnumHelper.GetEnumDesc(((CheckStatu)item.order_status));
                }
                else
                {
                    var list = dbContext.siger_wms_stocktake_order_detail.Where(f => f.order_number == item.order_number && f.status == (int)RowState.Valid);
                    foreach (var j in list)
                    {
                        if (j.stocktaked_quantity < j.quantity)
                        {
                            item.order_statusName = less;
                            break;
                        }
                        item.order_statusName = more;
                    }
                }
            }
            if (filter == CheckedStatu.LESS)
            {
                result = result.Where(f => f.order_statusName == less).ToList();
                totalCount = result.Count;
            }
            if (filter == CheckedStatu.MORE)
            {
                result = result.Where(f => f.order_statusName == more).ToList();
                totalCount = result.Count;
            }
            if (!isExport)
            {
                result = result.Skip((page - 1) * pageSize).Take(pageSize).ToList();
            }
            return result;
        }
        private IQueryable<siger_wms_stocktake_order> GetList(int projectId, CheckStatu state)
        {
            return GetList(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.order_status == (int)state); 
        }
        private List<ResponseGetCheckTotal> GetCheckResult(IQueryable<siger_wms_stocktake_order> data)
        {
            return (from info in data
             join wavehouse in dbContext.siger_wms_storage on info.storageid equals wavehouse.id
             into tmp1
             from wavehouseInfo in tmp1.DefaultIfEmpty()
             join creater in dbContext.siger_user on info.creator equals creater.id into tmp2
             from createrData in tmp2.DefaultIfEmpty()
             join checker in dbContext.siger_user on info.auditor equals checker.id into resultData
             from r in resultData.DefaultIfEmpty()
             select new ResponseGetCheckTotal
             {
                 id = info.id,
                 order_number = info.order_number,
                 creatername = createrData.nickname,
                 create_time = info.create_time,
                 auditname = r.nickname ?? "",
                 audittime = info.audit_time == null || info.audit_time == DateTime.MinValue ? "" : info.audit_time.ToString(UnixTimeHelper.DateTimeFormat),
                 order_status = info.order_status,
                 order_statusName = ""
             }).ToList();
        }
        public ResponseGetTotalInfo GetTotalInfo(int projectId)
        {
            //盘点中
            var checkingData = GetList(projectId, CheckStatu.Checking);
            //待审核
            var waittingData = GetList(projectId, CheckStatu.Waitting);
            //待盘点
            var checkedData = GetList(projectId, CheckStatu.Checked);
            //盘点完成
            //盘点完成只显示最近完成的10条
            var finishData = GetList(projectId, CheckStatu.Finish).OrderByDescending(f => f.update_time).Take(10);

            var waittingresult = GetCheckResult(waittingData);
            var checkedresult = GetCheckResult(checkedData); 
            var finishresult = GetCheckResult(finishData); 
            var checkingResult = GetCheckResult(checkingData);
            //transform count
            //种类、已盘数量
            foreach (var item in checkingResult)
            {
                GetCount(projectId, item);
            }
            foreach (var item in waittingresult)
            {
                GetCount(projectId, item);
            }
            foreach (var item in checkedresult)
            {
                GetCount(projectId, item);
            }
            foreach (var item in finishresult)
            {
                GetCount(projectId, item);
            }

            var start = new DateTime(DateTime.Now.Year, 1, 1);

            var finishDataCount = GetList(f => f.update_time > start && f.status == (int)RowState.Valid && f.projectid == projectId && f.order_status == (int)CheckStatu.Finish).Count();

            var result = new ResponseGetTotalInfo
            {
                waittingData = waittingresult,
                waittingCount = waittingData.Count(),
                checkedData = checkedresult,
                checkedCount = checkedData.Count(),
                finishData = finishresult,
                finishCount = finishDataCount,
                checkingData= checkingResult,
                checkingCount= checkingData.Count()
            };
            return result;
        }

        private void GetCount(int projectId, ResponseGetCheckTotal item)
        {
            var details = dbContext.siger_wms_stocktake_order_detail.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.orderid == item.id);
            int checkedCount = 0;
            foreach (var j in details)
            {
                if (j.stocktake_status == (int)CheckStatu.Finish)
                {
                    checkedCount++;
                }
            }
            item.typeCount = details.Count();
            item.checkedCount = checkedCount;
        }

        public ResponseGetDetail GetDetail(int id, int projectId)
        {
            if (!IsExist(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == id))
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            //获取表头信息
            var order = Get(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == id);
            if (order == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            var resultData = new ResponseGetDetail()
            {
                id = order.id,
                order_number = order.order_number,
                create_time = order.create_time,
                audittime = (order.audit_time == null|| order.audit_time==DateTime.MinValue)?"NA": order.audit_time.ToString(UnixTimeHelper.DateTimeFormat),
                auditname = GetUserName(order.auditor),
                order_status =order.order_status,
                order_statusName="",
                creatername= GetUserName(order.creator),
                storageid =order.storageid,
            };
            var storage = dbContext.siger_wms_storage.FirstOrDefault(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == order.storageid);
            if (storage == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            resultData.storagename = storage.name;

            //详情
            var details = dbContext.siger_wms_stocktake_order_detail.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.orderid == id);
            if (details == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }

            //盘盈、盘亏
            var more = EnumHelper.GetEnumDesc(CheckedStatu.MORE);
            var less = EnumHelper.GetEnumDesc(CheckedStatu.LESS);
            if (resultData.order_status != (int)CheckStatu.Finish)
            {
                resultData.order_statusName = EnumHelper.GetEnumDesc(((CheckStatu)resultData.order_status));
            }
            else
            {
                foreach (var j in details)
                {
                    if (j.stocktaked_quantity < j.quantity)
                    {
                        resultData.order_statusName = less;
                        break;
                    }
                    resultData.order_statusName = more;
                }
            }

            resultData.detail = new List<ResponseAppCheckDetail>();
            var result = new List<ResponseGetDetail>();
            foreach (var item in details.ToList())
            {
                var stock = dbContext.siger_wms_stock.FirstOrDefault(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == item.stockid);
                if (stock == null)
                {
                    continue;
                }
                if(int.TryParse(stock.manage_model, out int manageMode))
                {
                    resultData.detail.Add(new ResponseAppCheckDetail
                    {
                        inventorysn = item.material_pn ?? "",
                        batch = stock.batch_number ?? "",
                        sn = stock.serial_number ?? "",
                        totalCount = item.quantity,
                        checkCount = item.stocktaked_quantity,
                        businessID = stock.businessid,
                        businessName = GetBusinessName(stock.businessid, projectId),
                        id = item.id,
                        isChecked = item.stocktake_person == 0 ? 0 : 1,
                        manageMode = manageMode
                    });
                }
                else
                {
                    throw new BadRequestException(RequestEnum.ErrorManageModel);
                }
            }
            resultData.checkCount = resultData.detail.Count(f => f.isChecked != 0);
            resultData.totalCount = resultData.detail.Count;
            return resultData;
        }
    }
}

