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.Request;
using Siger.Middlelayer.WmsRepository.Response;

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

        public void Allocation(int id, List<node> nodes, int projectId, int userId, string no)
        {
            //若为序号发出,则拼接参数，保证后续逻辑一致性
            if (!string.IsNullOrEmpty(no))
            {
                var stock = dbContext.siger_wms_stock.FirstOrDefault(f => f.stock_state==(int)StockEnum.InWavehouse &&  f.status == (int)RowState.Valid && f.projectid == projectId && f.serial_number == no.Trim());
                if (stock == null)
                {
                    return;
                }
                nodes.Add(new node
                {
                    id = stock.id,
                    num = 1
                });
            }
            //更新详情记录
            var detailData = Get(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == id);
            if (detailData == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }

            var newCount = nodes.Sum(f => f.num);
            //数量过多
            if (detailData.quantity < detailData.transfer_quantity + newCount)
            {
                throw new BadRequestException(RequestEnum.CountError);
            }
            if (nodes.Exists(f => f.num <= 0))
            {
                throw new BadRequestException(RequestEnum.CountError);
            }
            var bill = dbContext.siger_wms_transfer_order.FirstOrDefault(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == detailData.orderid);
            if (bill == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            if (bill.order_status != (int)AlloactionStatu.Checked && bill.order_status != (int)AlloactionStatu.Alloaction &&
                bill.order_status != (int)AlloactionStatu.Alloactioning)
            {
                throw new BadRequestException(RequestEnum.ErrorState);
            }
            detailData.transfer_quantity += newCount;
            detailData.updator = userId;
            detailData.update_time = DateTime.Now;
            detailData.transfer_person = userId;
            detailData.transfer_time = DateTime.Now.ToString(UnixTimeHelper.DateTimeFormat);
            if (detailData.transfer_quantity != detailData.quantity)
            {
                //如果单据中有任何一个修改了状态
                //则将其他审核通过的记录的状态改为待调拨
                detailData.transfer_status = (int)AlloactionStatu.Alloactioning;
                var checkedData = GetList(f => f.id != detailData.id && f.status == (int)RowState.Valid && f.projectid == projectId && f.orderid == bill.id && f.transfer_status == (int)AlloactionStatu.Checked).ToList();
                checkedData.ForEach(f =>
                {
                    f.transfer_status = (int)AlloactionStatu.Alloaction;
                });
                foreach (var item in checkedData)
                {
                    Update(item);
                }
            }
            else
            {
                //待接收
                detailData.transfer_status = (int)AlloactionStatu.WaittingReceiving;
            }
            Update(detailData);

            //更新库存
            foreach (var item in nodes)
            {
                var stock = dbContext.siger_wms_stock.FirstOrDefault(f => f.stock_state == (int)StockEnum.InWavehouse && f.status == (int)RowState.Valid && f.projectid == projectId && f.id == item.id);
                if (stock == null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }
                //检测是否为同一物料、同一供应商
                if (stock.material_id != detailData.material_id || stock.businessid != detailData.businessid)
                {
                    throw new BadRequestException(RequestEnum.InventoryNotMatch);
                }

                //检测仓库是否为单据中的调出仓
                var locationData = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.id == stock.storage_location_id);
                if (locationData == null)
                {
                    throw new BadRequestException(RequestEnum.LocationNull);
                }
                if (locationData.storageid != bill.start_storage_id)
                {
                    throw new BadRequestException(RequestEnum.ReceivingStorageInError);
                }

                if (!int.TryParse(stock.manage_model, out int manageModel))
                {
                    throw new BadRequestException(RequestEnum.ErrorManageModel);
                }
                var managermode = (managemodel)(manageModel);
                switch (managermode)
                {

                    case managemodel.No:
                        //序号管理数量不得大于1
                        if (item.num > 1)
                        {
                            throw new BadRequestException(RequestEnum.CountError);
                        }
                        //修改stock状态为调拨中,在接收时改回在库，同时修改仓库、储位信息
                        stock.stock_state = (int)StockEnum.Allocation;
                        break;
                    case managemodel.Group:
                    case managemodel.Batch:
                        if (stock.quantity >= item.num)
                        {
                            stock.quantity -= item.num;
                        }
                        break;
                    default:
                        break;
                }
                stock.update_time = DateTime.Now;
                stock.updator = userId;
                dbContext.siger_wms_stock.Update(stock);

                //添加trace
                var tracedata = new siger_wms_stock_detail();
                tracedata.type = (int)traceType.Allocation;
                tracedata.billID = bill.order_number;
                tracedata.inventory = stock.material_id;
                tracedata.inventorySN = stock.material_pn;
                tracedata.inventoryName = stock.material_name;
                tracedata.allqty = detailData.quantity;
                tracedata.qty = item.num;
                tracedata.userid = userId;
                tracedata.username = GetUserName(userId);
                tracedata.updatetime = DateTime.Now;
                tracedata.state = (int)RowState.Valid;
                tracedata.locationid = bill.start_storage_id;
                tracedata.locationname = locationData.name;
                tracedata.inventorySpec = stock.material_spec;
                tracedata.state = (int)RowState.Valid;
                tracedata.projectid = projectId;
                tracedata.no = stock.serial_number;
                tracedata.batch = stock.batch_number;
                tracedata.businessid = stock.businessid;
                tracedata.businessName = GetBusinessName(stock.businessid, projectId);
                dbContext.siger_wms_stock_detail.Add(tracedata);

                //汇总库存
                SubtractStockChange(locationData.storageid, stock.material_id, item.num, projectId);
            }

            dbContext.SaveChanges();

            //更新header
            bill.update_time = DateTime.Now;
            bill.updator = userId;
            bill.order_status = (int)AlloactionStatu.Alloactioning;
            //如果所有调拨都完成,修改状态为待接收
            if (!IsExist(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.orderid == bill.id && f.quantity != f.transfer_quantity))
            {
                bill.order_status = (int)AlloactionStatu.WaittingReceiving;
            }
            dbContext.siger_wms_transfer_order.Update(bill);

            dbContext.SaveChanges();
        }

        public IEnumerable<ResponseGetAlloactionDetails> GetDetails(int showAll, int businessid, int id, int projectId, int page, int pageSize, out int totalValue, int start = 0, int end = 0, string pn = "")
        {
            var data = GetList(f => f.status == (int)RowState.Valid && f.projectid == projectId && f.transfer_status != (int)AlloactionStatu.Canceled);
            if (showAll != 0)
            {
                data = data.Where(f => f.transfer_status != (int)AlloactionStatu.Failed && f.transfer_status != (int)AlloactionStatu.Waitting &&
                                    f.transfer_status != (int)AlloactionStatu.Finish);
                //调拨
                if (showAll == 1)
                {
                    data = data.Where(f => f.transfer_status == (int)AlloactionStatu.Checked || f.transfer_status == (int)AlloactionStatu.Alloaction ||
                    f.transfer_status == (int)AlloactionStatu.Alloactioning);
                }
                //接收
                else
                {
                    var bills = dbContext.siger_wms_transfer_order.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId);
                    bills = bills.Where(f => f.order_status == (int)AlloactionStatu.Receiving || f.order_status == (int)AlloactionStatu.WaittingReceiving);
                    var billIDs = bills.Select(f => f.id).ToList();
                    data = data.Where(f => billIDs.Contains(f.orderid) && (f.transfer_status == (int)AlloactionStatu.Receiving || f.transfer_status == (int)AlloactionStatu.WaittingReceiving));
                }
            }
            if (0 != id)
            {
                data = data.Where(f => f.orderid == id);
            }
            if (businessid != 0)
            {
                data = data.Where(f => f.businessid == businessid);
            }
            if (0 != start)
            {
                var pids = dbContext.siger_wms_transfer_order.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId &&
                                                                    f.start_storage_id == start).Select(f => f.id).ToList();

                data = data.Where(f => pids.Contains(f.orderid));

            }
            if (0 != end)
            {
                var pids = dbContext.siger_wms_transfer_order.Where(f => f.status == (int)RowState.Valid && f.projectid == projectId &&
                                                                    f.end_storage_id == end).Select(f => f.id).ToList();
                data = data.Where(f => pids.Contains(f.orderid));
            }

            if (!string.IsNullOrEmpty(pn))
            {
                data = data.Where(f => f.material_pn == pn);
            }
            totalValue = data.Count();
            data = Paging(data, page, pageSize);
            var result = new List<ResponseGetAlloactionDetails>();
            var materialIDs = data.Select(f => f.material_id).Distinct().ToList();
            var manegeModeDic = dbContext.siger_tr_materials.Where(f => f.status == (int)RowState.Valid && f.projectId == projectId && materialIDs.Contains(f.id)).ToDictionary(f => f.id, f => f.manage_mode);
            var sendPerson = data.Select(f => f.transfer_person).Distinct().ToList();
            var receivePerson = data.Select(f => f.receive_person).Distinct().ToList();
            var sendDic = dbContext.siger_user.Where(f => f.status == (int)RowState.Valid && sendPerson.Contains(f.id)).ToDictionary(f => f.id, f => f.nickname);
            var receiveDic = dbContext.siger_user.Where(f => f.status == (int)RowState.Valid && receivePerson.Contains(f.id)).ToDictionary(f => f.id, f => f.nickname);

            var orderids = data.Select(f => f.orderid).ToList();
            var startStorageDic = dbContext.siger_wms_transfer_order.Where(f => f.projectid == projectId && f.status == (int)RowState.Valid && orderids.Contains(f.id)).
                ToDictionary(f => f.id, f => f.start_storage_id);
            var endStorageDic = dbContext.siger_wms_transfer_order.Where(f => f.projectid == projectId && f.status == (int)RowState.Valid && orderids.Contains(f.id)).
                ToDictionary(f => f.id, f => f.end_storage_id);

            foreach (var item in data)
            {
                item.receive_time = item.receive_time ?? "";
                item.transfer_time = item.transfer_time ?? "";

                var tmp = Mapper<siger_wms_transfer_order_detail, ResponseGetAlloactionDetails>.Map(item);

                if (startStorageDic.TryGetValue(item.orderid, out int v))
                {
                    tmp.startStorage = v;
                }
                if (endStorageDic.TryGetValue(item.orderid, out int endStorage))
                {
                    tmp.endStorage = endStorage;
                }

                tmp.stateName = EnumHelper.GetEnumDesc((AlloactionStatu)tmp.transfer_status);
                if (manegeModeDic.TryGetValue(tmp.material_id, out string value))
                {
                    try
                    {
                        tmp.manegeModeName = EnumHelper.GetEnumDesc((managemodel)int.Parse(value));
                    }
                    catch (Exception)
                    {

                    }
                }
                if (item.receive_person != 0)
                {
                    if (receiveDic.TryGetValue(item.receive_person, out string recName))
                    {
                        tmp.receive_personName = recName;
                    }
                }
                else
                {
                    tmp.receive_personName = "";
                }
                if (item.transfer_person != 0)
                {
                    if (sendDic.TryGetValue(item.transfer_person, out string transName))
                    {
                        tmp.transfer_personName = transName;
                    }
                }
                else
                {
                    tmp.transfer_personName = "";
                }
                result.Add(tmp);
            }
            return result;
        }
    }
}

