using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Repository;
using System.IO;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common.AppSettings;
using Siger.Middlelayer.Log;
using System.Linq.Expressions;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.WmsRepository.Entities;
using Siger.Middlelayer.WmsRepository.Repositories.Interface;
using Siger.Middlelayer.WmsRepository.Request;
using Siger.Middlelayer.WmsRepository.Response;
using Siger.Middlelayer.Repository.Repositories.Interface;

namespace Siger.ApiWMS.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    public class StockController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly Isiger_wms_stock_detailRepository trace;
        private readonly Isiger_wms_stock_access_orderRepository order;
        private readonly Isiger_wms_stock_access_order_detailRepository orderdetail;
        private readonly Isiger_wms_stockRepository stock;
        private readonly Isiger_wms_storage_locationRepository location;
        private readonly Isiger_wms_stock_quantity_change_historyRepository quantityChange;
        private readonly Isiger_wms_stocktake_orderRepository stocktake;
        private readonly ISigerProjectUserRepository _userRepository;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="unitOfWork"></param>
        /// <param name="trace"></param>
        /// <param name="order"></param>
        /// <param name="orderdetail"></param>
        /// <param name="stock"></param>
        /// <param name="location"></param>
        /// <param name="locationType"></param>
        /// <param name="quantityChange"></param>
        /// <param name="stocktake"></param>
        /// <param name="userRepository"></param>
        public StockController(IUnitOfWork unitOfWork, Isiger_wms_stock_detailRepository trace, Isiger_wms_stock_access_orderRepository order, Isiger_wms_stock_access_order_detailRepository orderdetail, Isiger_wms_stockRepository stock, Isiger_wms_storage_locationRepository location, Isiger_wms_storage_location_typeRepository locationType, Isiger_wms_stock_quantity_change_historyRepository quantityChange, Isiger_wms_stocktake_orderRepository stocktake
            ,ISigerProjectUserRepository userRepository)
        {
            _unitOfWork = unitOfWork;
            this.trace = trace;
            this.order = order;
            this.orderdetail = orderdetail;
            this.stock = stock;
            this.location = location;
            this.quantityChange = quantityChange;
            this.stocktake = stocktake;
            _userRepository = userRepository;
        }
        /// <summary>
        /// 获取出入库单详情
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetBillList(int businessID, WaveHouseType type, int dataFilter, int wavehouseid, string billCode, int inventoryid, string originOrderNumber, DateTime start, DateTime end, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            var result = trace.GetDetails(businessID, type, dataFilter, wavehouseid, billCode, inventoryid, originOrderNumber, start, end, ProjectId, UserId, out int count, page, pageSize);
            return new PagedObjectResult(result, count, page, pageSize);
        }

        /// <summary>
        /// 出入库记录详情
        /// </summary>
        /// <param name="businessID"></param>
        /// <param name="type">trace类型</param>
        /// <param name="billCode"></param>
        /// <param name="inventorySN"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetBillTrace(int businessID, traceType type, string billCode, string inventorySN, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);

            var data = trace.GetList(f => f.type == (int)type && f.state == (int)RowState.Valid && f.projectid == ProjectId);
            if (!string.IsNullOrEmpty(billCode))
            {
                data = data.Where(f => f.billID == billCode.Trim());
            }
            if (!string.IsNullOrEmpty(inventorySN))
            {
                data = data.Where(f => f.inventorySN == inventorySN.Trim());
            }
            if (businessID != 0)
            {
                data = data.Where(f => f.businessid == businessID);
            }
            var count = data.Count();
            var result = data.Skip((page - 1) * pageSize).Take(pageSize).ToList();

            foreach (var item in result)
            {
                item.username = _userRepository.Get(f => f.mid == item.userid)?.name ?? "";
            }
            return new PagedObjectResult(result, count, page, pageSize);
        }


        /// <summary>
        /// TODO迭代
        /// 入库
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult CheckIn([FromBody]RequestWaveHousing req)
        {
            //var isReceiving = req.isReceiving == 1;
            //var result = stock.CheckIn(ProjectId, UserId, req, location, isReceiving);
            req.ProjectId = ProjectId;
            req.UserId = UserId;
            var result = stock.CheckIn(req);
            return new ObjectResult(result);
        }

        /// <summary>
        /// 出库
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult CheckOut([FromBody]RequestBatchOut req)
        {
            orderdetail.CheckOut(req.id, req.inventories, UserId, ProjectId, req.type, req.code);

            return Ok();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="businessID"></param>
        /// <param name="billCode"></param>
        /// <param name="invantorysn"></param>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <param name="billType">单据类型</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockByInvantory(int businessID, string billCode, string invantorysn, managemodel type, string filter, traceType billType)
        {
            IEnumerable<ResponseeInventory> result;
            if (string.IsNullOrEmpty(billCode))
            {
                result = stock.GetList(0, invantorysn, ProjectId, type, filter, businessID);
            }
            else
            {
                int storageid = 0;
                switch (billType)
                {
                    case traceType.WaveHousing:
                    case traceType.WaveHousingOut:
                        var entity = order.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.order_number == billCode.Trim());
                        if (entity == null)
                        {
                            throw new BadRequestException(CommonEnum.NoData);
                        }
                        storageid = entity.storageid;
                        break;
                    case traceType.Use:
                    case traceType.Return:
                    case traceType.LocationChange:
                    case traceType.StockChange:
                        break;
                    case traceType.Check:

                        var stocktakeentiry = stocktake.Get(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.order_number == billCode.Trim());
                        if (stocktakeentiry == null)
                        {
                            throw new BadRequestException(CommonEnum.NoData);
                        }
                        storageid = stocktakeentiry.storageid;
                        break;
                    default:
                        break;
                }
                result = stock.GetList(storageid, invantorysn, ProjectId, type, filter, businessID);
            }
            return new ObjectResult(result);
        }
        /// <summary>
        /// 获取库存数据
        /// </summary>
        /// <param name="businessid"></param>
        /// <param name="batch"></param>
        /// <param name="no"></param>
        /// <param name="storageid"></param>
        /// <param name="invantorysn"></param>
        /// <param name="locationid"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>~
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockList(int businessid, string batch, string no, int storageid, string invantorysn, int locationid, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);

            var result = stock.GetList(businessid, storageid, invantorysn, locationid, page, pageSize, ProjectId, out int totalCount, true, batch, no);
            return new PagedObjectResult(result, totalCount, page, pageSize);
        }
        /// <summary>
        /// 获取库存数据
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockListForApp(string code)
        {
            var result = stock.GetListForApp(code, ProjectId);
            return new ObjectResult(result);
        }


        /// <summary>
        /// 库存调整
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult ChangeStockNumber([FromBody]RequestChangeStockNumbewr req)
        {
            var username = orderdetail.GetUserName(UserId);
            foreach (var item in req.nodes)
            {
                //更新记录数量
                var entity = stock.Get(f => f.id == item.id && f.status == (int)RowState.Valid && f.projectid == ProjectId && f.manage_model != ((int)managemodel.No).ToString());
                if (entity == null)
                {
                    throw new BadRequestException(CommonEnum.NoData);
                }

                //添加变更记录
                quantityChange.Insert(new siger_wms_stock_quantity_change_history
                {
                    storage_location_id = entity.storage_location_id,
                    manage_mode = entity.manage_model,
                    material_id = entity.material_id,
                    material_name = entity.material_name,
                    material_pn = entity.material_pn,
                    material_spec = entity.material_spec,
                    batch_serial = entity.batch_number,
                    before_adjust_quantity = entity.quantity,
                    after_adjust_quantity = item.num,
                    reason = req.reason,
                    adjust_person = username?.ToString(),
                    adjust_time = DateTime.Now.ToString(UnixTimeHelper.DateTimeFormat),
                    create_time = DateTime.Now.ToString(UnixTimeHelper.DateTimeFormat),
                    creator = username?.ToString(),
                    projectid = ProjectId,
                    businessid = entity.businessid,
                    businessName = orderdetail.GetBusinessName(entity.businessid, ProjectId)
                });
                var locationdata = location.Get(f => f.id == entity.storage_location_id && f.status == (int)RowState.Valid);
                trace.Insert(new siger_wms_stock_detail
                {
                    type = (int)traceType.StockChange,
                    inventory = entity.material_id,
                    inventoryName = entity.material_name,
                    inventorySN = entity.material_pn,
                    inventorySpec = entity.material_spec,
                    locationid = entity.storage_location_id,
                    locationname = locationdata.name?.ToString(),
                    batch = entity.batch_number,
                    no = entity.serial_number,
                    userid = UserId,
                    username = username.ToString(),
                    updatetime = DateTime.Now,
                    state = (int)RowState.Valid,
                    projectid = ProjectId,
                    allqty = entity.quantity,
                    qty = item.num,
                    businessid = entity.businessid,
                    businessName = orderdetail.GetBusinessName(entity.businessid, ProjectId)
                });

                //当前数量小于待修改的数量
                //即当前库存大于实际库存
                //需要将现有库存改小
                if (entity.quantity > item.num)
                {
                    trace.SubtractStockChange(locationdata.storageid, entity.material_id, (entity.quantity - item.num), ProjectId);
                }
                if (entity.quantity < item.num)
                {
                    trace.AddStockChange(locationdata.storageid, entity.material_id, (item.num - entity.quantity), ProjectId);
                }

                entity.quantity = item.num;
                entity.update_time = DateTime.Now;
                entity.updator = UserId;
                stock.Update(entity);
            }
            if (_unitOfWork.Commit() <= 0)
                throw new BadRequestException(CommonEnum.Fail);
            return Ok();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="businessid"></param>
        /// <param name="locationid"></param>
        /// <param name="sn"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public IActionResult GetChangeHistory(int businessid, int locationid, string sn, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            var result = quantityChange.GetChangeHistory(businessid, ProjectId, locationid, sn, page, pageSize, out int totalCount);

            return new PagedObjectResult(result, totalCount, page, pageSize);
        }
        /// <summary>
        ///  入库汇总
        /// </summary>
        /// <param name="requestStock"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult StockInTotal([FromBody]RequestStock requestStock)
        {
            var data = stock.GetStockTotal(traceType.WaveHousing.GetHashCode(), ProjectId, requestStock.tId, requestStock.wid, requestStock.start, requestStock.end, requestStock.page, requestStock.pagesize, out int totalCount);

            return new PagedObjectResult(data, totalCount, requestStock.page, requestStock.pagesize);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tId"></param>
        /// <param name="wid"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportStockInTotal(int tId, int wid, string start, string end)
        {
            //var data = stock.GetStockTotal(traceType.WaveHousing.GetHashCode(), ProjectId, tId, wid, start, end, 0, 0, out int totalCount,false);

            return Ok();
        }

        /// <summary>
        /// 入库库明细
        /// </summary>
        /// <param name="requestStock"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult StockInDetails([FromBody]RequestStock requestStock)
        {
            var data = stock.GetStockDetails(traceType.WaveHousing.GetHashCode(), ProjectId, requestStock.tId, requestStock.wid, requestStock.start, requestStock.end, requestStock.page, requestStock.pagesize, out int totalCount);

            return new PagedObjectResult(data, totalCount, requestStock.page, requestStock.pagesize);
        }
        /// <summary>
        ///  出库汇总
        /// </summary>
        /// <param name="requestStock"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult StockOutTotal([FromBody]RequestStock requestStock)
        {
            var data = stock.GetStockTotal(traceType.WaveHousingOut.GetHashCode(), ProjectId, requestStock.tId, requestStock.wid, requestStock.start, requestStock.end, requestStock.page, requestStock.pagesize, out int totalCount);

            return new PagedObjectResult(data, totalCount, requestStock.page, requestStock.pagesize);

        }
        /// <summary>
        /// 出库明细
        /// </summary>
        /// <param name="requestStock"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult StockOutDetails([FromBody]RequestStock requestStock)
        {
            var data = stock.GetStockDetails(traceType.WaveHousingOut.GetHashCode(), ProjectId, requestStock.tId, requestStock.wid, requestStock.start, requestStock.end, requestStock.page, requestStock.pagesize, out int totalCount);

            return new PagedObjectResult(data, totalCount, requestStock.page, requestStock.pagesize);
        }



        /// <summary>
        /// 库存汇总
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult StockSummary(int id, int page, int pageSize)
        {
            Utility.CheckPage(page, pageSize);
            var result = stock.StockSummary(id, ProjectId, page, pageSize, out int totalCount);

            return new PagedObjectResult(result, totalCount, page, pageSize);
        }
        /// <summary>
        /// 库存汇总导出
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportStockSummary(int id)
        {
            //查询数据
            var result = stock.StockSummary(id, ProjectId, 0, 0, out int totalCount, false);

            //获取配置信息
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            string temporaryFileName = $"stocksummaryinfo_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            //绑定数据并导出
            var index = 1;
            var exportData = new List<ExportStockSummary>();

            foreach (var item in result)
            {
                var tmp = Mapper<ResponseStockSummary, ExportStockSummary>.Map(item);
                tmp.id = index++;
                exportData.Add(tmp);
            }

            var helper = new EpPlusExcelHelper<ExportStockSummary>();
            try
            {
                helper.GenerateExcel(exportData, fileName);

                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportStock failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        /// <summary>
        /// 库存详情
        /// </summary>
        /// <param name="businessid"></param>
        /// <param name="storageid"></param>
        /// <param name="invantorysn"></param>
        /// <param name="locationid"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportStockDetails(int businessid, int storageid, string invantorysn, int locationid)
        {
            //查询数据
            var result = stock.GetList(businessid, storageid, invantorysn, locationid, 0, 0, ProjectId, out int totalCount, false);

            //获取配置信息
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            string temporaryFileName = $"stockdetailsinfo_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            //绑定数据并导出
            var index = 1;
            var exportData = new List<ExportStockData>();

            foreach (var item in result)
            {
                var tmp = Mapper<ResponseeInventory, ExportStockData>.Map(item);
                //处理序号、批次显示问题
                if (item.manage_model == ((int)managemodel.No).ToString())
                {
                    tmp.batch_number = item.serial_number;
                }

                tmp.id = index++;
                exportData.Add(tmp);
            }

            var helper = new EpPlusExcelHelper<ExportStockData>();
            try
            {
                helper.GenerateExcel(exportData, fileName);

                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportStock failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }

        /// <summary>
        /// 入库图表
        /// </summary>
        /// <param name="storageid"></param>
        /// <param name="sn"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockChangeHistory(int storageid, string sn, DateTime start, DateTime end)
        {
            var result = stock.GetStockChangeHistory(storageid, sn, start, end, ProjectId, traceType.WaveHousing);
            return new ObjectResult(result);
        }

        /// <summary>
        /// 出库图表
        /// </summary>
        /// <param name="storageid"></param>
        /// <param name="sn"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockOutChangeHistory(int storageid, string sn, DateTime start, DateTime end)
        {
            var result = stock.GetStockChangeHistory(storageid, sn, start, end, ProjectId, traceType.WaveHousingOut);
            return new ObjectResult(result);
        }

        /// <summary>
        /// 标签补印
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetQRInfo(string value, managemodel type)
        {
            string code = "";
            Expression<Func<siger_wms_stock, bool>> filter = f => f.manage_model == ((int)type).ToString() && f.status == (int)RowState.Valid && f.projectid == ProjectId;
            Expression<Func<siger_wms_stock, bool>> batchExpression = f => true;
            Expression<Func<siger_wms_stock, bool>> noExpression = f => true;

            if (!string.IsNullOrEmpty(value))
            {
                switch (type)
                {
                    case managemodel.Batch:
                        batchExpression = f => f.batch_number == value.Trim();
                        break;
                    case managemodel.No:
                        noExpression = f => f.serial_number == value.Trim();
                        break;
                    case managemodel.Group:
                        break;
                    default:
                        break;
                }
            }

            var resultFilter = filter.And(batchExpression).And(noExpression);
            var entity = stock.GetList(resultFilter).FirstOrDefault();
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            if (entity.manage_model == ((int)managemodel.Batch).ToString())
            {
                code = entity.batch_number;
            }
            if (entity.manage_model == ((int)managemodel.No).ToString())
            {
                code = entity.serial_number;
            }
            var result = new ResponseCheckIn
            {
                code = code,
                material_name = entity.material_name,
                material_spec = entity.material_spec,
                time = entity.update_time.ToString(UnixTimeHelper.DateFormat)
            };
            return new ObjectResult(result);
        }
    }
}