using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Filters;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;
using Siger.Middlelayer.WmsRepository.Entities;
using Siger.Middlelayer.WmsRepository.Repositories.Interface;
using Siger.Middlelayer.WmsRepository.Request;

namespace Siger.ApiWMS.Controllers
{
    /// <summary>
    /// 仓库
    /// </summary>
    public class WaveHouseController : BaseController
    {
        private readonly Isiger_wms_storageRepository storage;
        private readonly Isiger_wms_storage_location_typeRepository locationtype;
        private readonly Isiger_wms_stockRepository stock;
        private readonly Isiger_wms_storage_typeRepository waveHouseType;
        private readonly Isiger_wms_storage_locationRepository location;
        private readonly IUnitOfWork _unitOfWork;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storage"></param>
        /// <param name="locationtype"></param>
        /// <param name="stock"></param>
        /// <param name="waveHouseType"></param>
        /// <param name="location"></param>
        /// <param name="unitOfWork"></param>
        public WaveHouseController(Isiger_wms_storageRepository storage, Isiger_wms_storage_location_typeRepository locationtype, Isiger_wms_stockRepository stock, Isiger_wms_storage_typeRepository waveHouseType, Isiger_wms_storage_locationRepository location, IUnitOfWork unitOfWork)
        {
            this.storage = storage;
            this.locationtype = locationtype;
            this.stock = stock;
            this.waveHouseType = waveHouseType;
            this.location = location;
            _unitOfWork = unitOfWork;
        }

        /// <summary>
        /// 获取仓库列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetWaveHouseList( string name, int typeid, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            var result = storage.GetWaveHouseList(ProjectId, name, typeid, page, pageSize, out int totalCount);
            return new PagedObjectResult(result, totalCount, page, pageSize);
        }
        /// <summary>
        /// 新增仓库
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddStorage([FromBody]RequestAddStorage req)
        {
            if (storage.IsExist(f => f.name == req.name && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            //检测typeid
            if (!waveHouseType.IsExist(f => f.status == (int)RowState.Valid && f.id == req.typeid && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.StorageTypeIDNotExist);
            }
            if (storage.IsExist(f => f.name == req.name && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            storage.Insert(new siger_wms_storage
            {
                typeid = req.typeid,
                name = req.name,
                serial_number = Utility.GenSerialNumber(),
                address = req.address,
                manager = req.linkman,
                creator = UserId,
                create_time = DateTime.Now,
                updator = UserId,
                update_time = DateTime.Now,
                projectid = ProjectId,
                status = req.status ? 1 : 0,
                phone = req.phone,
                mobile = req.mobile,
                description = req.description
            });
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 更新仓库
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UpdateStorage([FromBody]RequestUpdateStorage req)
        {
            if (storage.IsExist(f => f.name == req.name & f.id != req.id && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            //检测typeid
            if (!waveHouseType.IsExist(f => f.status == (int)RowState.Valid && f.id == req.typeid && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.StorageTypeIDNotExist);
            }
            if (storage.IsExist(f => f.name == req.name && f.id != req.id && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            var entity = storage.GetList(f => f.id == req.id && f.projectid == ProjectId).FirstOrDefault();
            if (entity == null)
                throw new BadRequestException(CommonEnum.NoData);

            //update start
            entity.typeid = req.typeid;
            entity.name = req.name;
            entity.address = req.address;
            entity.manager = req.linkman;
            entity.updator = UserId;
            entity.update_time = DateTime.Now;
            entity.projectid = ProjectId;
            entity.status = req.status ? 1 : 0;
            entity.phone = req.phone;
            entity.mobile = req.mobile;
            entity.description = req.description;

            //update end
            storage.Update(entity);

            //更新所有location
            var dic = new Dictionary<int, string>();
            var pids = new List<int>();
            //获取第一级储位
            //依次更新每一级储位
            var locations = location.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId&f.storageid==entity.id&&f.parentid==0);
            foreach (var item in locations)
            {
                item.name = entity.name + " -> " + item.realname;
                location.Update(item);
                dic.Add(item.id, item.name);
                pids.Add(item.id);
            }
            //重新生成子级
            while (pids.Count() != 0)
            {
                var data = location.GetList(f => pids.Contains(f.parentid) && f.projectid == ProjectId).ToList();
                pids = data.Select(f => f.id).ToList();

                foreach (var item in data)
                {
                    if (dic.TryGetValue(item.parentid, out string parentName))
                    {
                        item.name = parentName + " -> " + item.realname;
                        location.Update(item);
                    }
                }
                dic = data.ToDictionary(f => f.id, f => f.name);
            }

            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 删除仓库
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult DelStorage([FromBody]RequestDelStorage req)
        {
            if (!storage.IsExist(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.NoData);
            }

            var entity = storage.Get(f => f.id == req.id && f.projectid == ProjectId);
            if (entity == null)
                throw new BadRequestException(CommonEnum.NoData);

            if (location.GetList(q => q.projectid == ProjectId && q.status == (int)RowState.Valid && q.storageid == req.id).Any())
            {
                throw new BadRequestException(RequestEnum.WavehouseBindLocationData);
            }

            entity.status = (int)RowState.Valid;
            storage.Update(entity);
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }
        /// <summary>
        /// 导出仓库列表
        /// </summary>
        /// <param name="name"></param>
        /// <param name="typeid"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportStorage(string name, int typeid)
        {
            var result = storage.GetWaveHouseList(ProjectId, name, typeid, 0, 0, out int totalCount, true).ToList();
            var type = new Dictionary<int, string>();
            waveHouseType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList().ForEach(f =>
            {
                type.Add(f.id, f.name);
            });
            int index = 1;
            //调整序号
            var list = new List<StorageList>();
            foreach (var item in result)
            {
                list.Add(new StorageList
                {
                    id = index++,
                    typename = item.typename,
                    name = item.name,
                    serial_number = item.serial_number,
                    address = item.address,
                    manager = item.manager,
                    phone = item.phone,
                    mobile = item.mobile,
                    status = item.status == (int)RowState.Invalid ? "是" : "否",
                    description = item.description
                });
            }
            var fileName = Utility.GetExcelFileName("Storage");
            var helper = new EpPlusExcelHelper<StorageList>();
            try
            {
                helper.GenerateExcel(list, fileName);

                return new ObjectResult(Utility.GetExcelFileDisplayName(Path.GetFileName(fileName)));
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportMaterials failed, error: " + e.Message);
                throw new BadRequestException(RequestEnum.ExportFailed);
            }
            finally
            {
                helper.Dispose();
            }
        }
        /// <summary>
        /// .导入仓库TODO重构
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> ImportStorage([FromForm]IFormFile file)
        {
            if(file == null)
            {
                file = HttpContext.Request.Form.Files.First();
            }
            var filePath = Utility.GetExcelTmpFileName("Storage", file.FileName);
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }
            IEnumerable<StorageList> list;
            var helper = new EpPlusExcelHelper<StorageList>(filePath);
            try
            {
                var messages = helper.CheckExcel();
                if (messages.Any())
                {
                    throw new Exception(string.Join(';', messages));
                }
                list = helper.ConvertSheetToList().ToList();
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportMaterials failed, error: " + e.Message);
                throw new Exception(EnumHelper.GetEnumDesc(RequestEnum.ImportFailed));
            }
            finally
            {
                helper.Dispose();
            }
            var type = new Dictionary<string, int>();
            waveHouseType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList().ForEach(f =>
            {
                type.Add(f.name, f.id);
            });
            var err = new StringBuilder();
            foreach (var item in list)
            {
                int id = item.id;
                //必填项校验

                try
                {
                    if (storage.IsExist(f => f.name == item.name && f.projectid == ProjectId))
                        throw new Exception(EnumHelper.GetEnumDesc(CommonEnum.RecordExits));
                    //is exist//name、code
                    storage.Insert(new siger_wms_storage
                    {
                        typeid = type[item.typename],
                        name = item.name,
                        serial_number = item.serial_number,
                        address = item.address,
                        manager = item.manager,
                        phone = item.phone,
                        mobile = item.mobile,
                        status = item.status == "是" ? (int)RowState.Invalid : (int)RowState.Valid,
                        description = item.description,
                        create_time = DateTime.Now,
                        creator = UserId,
                        update_time = DateTime.Now,
                        updator = UserId,
                        projectid = ProjectId
                    });
                }
                catch (Exception e)
                {
                    err.Append($"序号:[{id}]导入失败:{e.Message}\n");
                }

            }
            if (!string.IsNullOrEmpty(err.ToString()))
            {
                throw new Exception(err.ToString());
            }
            if (_unitOfWork.Commit() < 0)
                throw new BadRequestException(CommonEnum.Fail);
            return new OkResult();
        }


        /// <summary>
        /// 获取物料列表
        /// </summary>
        /// <param name="name"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetStockList(string name, int page = 1, int pageSize = 10)
        {
            Utility.CheckPage(page, pageSize);
            if (string.IsNullOrEmpty(name))
            {
                return new ObjectResult(stock.GetPagedList(page, pageSize, f => f.status == (int)RowState.Valid && f.projectid == ProjectId));
            }
            else
            {
                return new ObjectResult(stock.GetPagedList(page, pageSize, f => f.material_name.Contains(name) && f.status == (int)RowState.Valid && f.projectid == ProjectId));
            }
        }

        /// <summary>
        /// 获取仓库类别树
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetWaveHouseTypeTree()
        {
            var list = waveHouseType.GetWavehouseTypeTree(ProjectId);
            var response = new ResponseLevelSectionChildren(Utility.ConvertToTree(list));

            return new ObjectResult(response);
        }


        /// <summary>
        /// 仓库类别列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetWaveHouseTypeList(int page, int pageSize)
        {
            Utility.CheckPage(page, pageSize);
            var dic = new Dictionary<int, string>();
            var list = waveHouseType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).ToList();
            foreach (var item in list)
            {
                dic.Add(item.id, item.name);
            }
            var result = new List<RequestGetWaveHouseTypeList>();
            foreach (var item in list)
            {
                string parent = "";
                if (item.parentid == 0)
                {
                    parent = "0";
                }
                else
                {
                    parent = dic[item.parentid];
                }
                result.Add(new RequestGetWaveHouseTypeList
                {
                    id = item.id,
                    name = item.name,
                    parentName = parent,
                    pid = item.parentid
                });
            }
            var count = result.Count;
            result = result.Skip((page - 1) * pageSize).Take(pageSize).ToList();
            return new PagedObjectResult(result, count, page, pageSize);
        }

        /// <summary>
        /// 新增仓库类别
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddStorageType([FromBody]RequestAddsiger_wms_storage_type req)
        {
            if (waveHouseType.IsExist(f => f.name == req.name && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            if (req.parentid != 0)
            {
                if (!waveHouseType.IsExist(f => f.id == req.parentid && f.status == (int)RowState.Valid && f.projectid == ProjectId))
                    throw new BadRequestException(RequestEnum.NoParentStorageType);
                
                //层级不能超过两级
                if(waveHouseType.IsExist(f => f.status == (int)RowState.Valid && f.projectid == ProjectId&&f.id==req.parentid&&f.parentid!=0))
                {
                    throw new BadRequestException(RequestEnum.StorageType2More);
                }
            }
            waveHouseType.Insert(new siger_wms_storage_type
            {
                name = req.name,
                parentid = req.parentid,
                creator = UserId,
                create_time = DateTime.Now,
                updator = UserId,
                update_time = DateTime.Now,
                projectid = ProjectId,
                status = (int)RowState.Valid
            });
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult UpdateStorageType([FromBody]RequestUpdatesiger_wms_storage_type req)
        {
            var entity = waveHouseType.GetList(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == ProjectId).FirstOrDefault();
            if (entity == null)
                throw new BadRequestException(CommonEnum.NoData);
            if (entity.id == req.parentid)
                throw new BadRequestException(RequestEnum.LocationPidCanNotBySelf);
            if (waveHouseType.IsExist(f => f.name == req.name && f.id != req.id && f.projectid == ProjectId))
                throw new BadRequestException(CommonEnum.RecordExits);
            //update start
            entity.id = req.id;
            entity.name = req.name;
            entity.parentid = req.parentid;
            entity.updator = UserId;
            entity.update_time = DateTime.Now;

            //update end
            waveHouseType.Update(entity);
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult DelStorageType([FromBody]RequestDelsiger_wms_storage_type req)
        {
            if (!waveHouseType.IsExist(f => f.id == req.id && f.status == (int)RowState.Valid && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            if (storage.IsExist(f => f.status == (int)RowState.Valid && f.typeid == req.id && f.projectid == ProjectId))
            {
                throw new BadRequestException(CommonEnum.LayerNotClean);
            }
            var entity = waveHouseType.Get(f => f.id == req.id && f.projectid == ProjectId);

            entity.status = (int)RowState.Invalid;
            entity.update_time = DateTime.Now;
            entity.updator = UserId;

            waveHouseType.Update(entity);
            if (_unitOfWork.Commit() > 0)
                return Ok();
            throw new BadRequestException(CommonEnum.Fail);
        }

        /// <summary>
        /// 获取仓库类型名称
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetWaveHouseTypeName()
        {
            var result = waveHouseType.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId).Select(f => new { f.id, f.name });

            return new ObjectResult(result);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IActionResult GetWaveHouseNameList()
        {
            var result = storage.GetList(f => f.status == (int)RowState.Valid && f.projectid == ProjectId && f.projectid == ProjectId).Select(f => new
            {
                f.id,
                f.name,
            }).ToList();
            return new ObjectResult(result);
        }
    }
}