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

namespace Siger.ApiConfig.Controller
{
    public class MaterialsController : BaseController
    {
        private readonly ISigerTrMaterialsRepository _materialsRepository;
        private readonly Isiger_wms_bussinese_contactsRepository _bussineseContactsRepository;
        private readonly ISigerTrMaterialTypeRepository _materialTypeRepository;
        private readonly ISigerDict _sigerDict;
        private readonly ISigerTrProductStructureRepository _sigerTrProduct;
        private readonly ISigerProjectRepository _projectRepository;
        private readonly IUnitOfWork _unitOfWork;
        public MaterialsController(IUnitOfWork unitOfWork, ISigerTrMaterialsRepository materialsRepository
            , ISigerTrMaterialTypeRepository materialTypeRepository, ISigerDict sigerDict,
            ISigerTrProductStructureRepository sigerTrProduct, Isiger_wms_bussinese_contactsRepository bussineseContactsRepository
            , ISigerProjectRepository projectRepository)
        {
            _unitOfWork = unitOfWork;
            _materialsRepository = materialsRepository;
            _materialTypeRepository = materialTypeRepository;
            _sigerDict = sigerDict;
            _sigerTrProduct = sigerTrProduct;
            _bussineseContactsRepository = bussineseContactsRepository;
            _projectRepository = projectRepository;
        }

        [HttpGet]
        public IActionResult GetList(string name, string exp, string typeid, string pn, int page = 1, int pageSize = 10)
        {
            var exp1 = exp.ToInt();
            var pType = typeid.ToInt();
            var data = _materialsRepository.GetPagedListEx(name, exp1, pn, pType, ProjectId, page, pageSize);
            var materialList = new List<Material>();
            foreach (var material in data.Data)
            {
                var suppliers = _bussineseContactsRepository.GetPnSupplierIds(ProjectId, material.id);
                material.supplier = string.Join(',', suppliers.Select(t => t.id).ToList());
                material.supplier_value = string.Join(',', suppliers.Select(t => t.title).ToList());
                materialList.Add(material);
            }
            return new PagedObjectResult(materialList, data.Total, page, pageSize);
        }

        /// <summary>
        /// 获取全部层级组成的tcode字符串
        /// </summary>
        /// <param name="parentid"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        private List<siger_tr_material_type> GetMaterialTypeAllParent(int parentid, List<siger_tr_material_type> entities)
        {
            var entity = _materialTypeRepository.Get(t => t.id == parentid && t.projectId == ProjectId && t.status == (int)RowState.Valid);
            if (entity != null && entity.parentid > 0)
            {
                entities.Add(entity);
                return GetMaterialTypeAllParent(entity.parentid, entities);
            }
            else
            {
                return entities;
            }
        }

        private string GetMaterialsPn(int parentid)
        {
            string code = "";
            var entities = new List<siger_tr_material_type>();
            var lists = GetMaterialTypeAllParent(parentid, entities);
            if (lists != null && lists.Any())
            {
                lists.Reverse();
                foreach (var item in lists)
                {
                    code += item.tcode;
                }
            }
            var maxid = _materialsRepository.GetMaxId();
            return code + (maxid > 0 ? (maxid + 1) : 1).ToString("000000");
        }

        [HttpPost]
        public IActionResult Add([FromBody] RequestAddMaterials request)
        {
            if (request.min_stock < 0 || request.max_stock < 0)
            {
                throw new BadRequestException(RequestEnum.StcokNotLessThanZero);
            }
            var min_stock = (int)request.min_stock;
            var max_stock = (int)request.max_stock;
            if (min_stock - request.min_stock != 0 || max_stock - request.max_stock != 0)
            {
                throw new BadRequestException(RequestEnum.StockMustBeInteger);
            }
            if ((request.min_stock > 0 || request.max_stock > 0) && request.min_stock > request.max_stock)
            {
                throw new BadRequestException(RequestEnum.MaxMinStockError);
            }
            if (_materialsRepository.IsExist(q => q.name == request.name && q.spec == request.spec && q.status == (int)RowState.Valid && q.projectId == ProjectId))
                throw new BadRequestException(RequestEnum.MaterialNameSpecExist);
            if (_materialsRepository.IsExist(q => q.pn == request.pn && q.status == (int)RowState.Valid && q.projectId == ProjectId))
                throw new BadRequestException(RequestEnum.MaterialPnExist);

            if (_materialTypeRepository.IsExist(t => t.parentid == request.typeid && t.status == (int)RowState.Valid))
                throw new BadRequestException(RequestEnum.AddMaterialsTypeIdError);
            
            if (request.is_first == "1" && string.IsNullOrEmpty(request.priority))
                throw new BadRequestException(RequestEnum.PriorityIsEmpty);

            var entity = new siger_tr_materials
            {
                typeid = request.typeid,
                name = request.name,
                spec = request.spec,
                pn = string.IsNullOrWhiteSpace(request.pn) ? GetMaterialsPn(request.typeid) : request.pn,
                supplier = string.IsNullOrEmpty(request.supplier) ? "" : request.supplier,
                manage_mode = request.manage_mode ?? "",
                unit = request.unit ?? "",
                conv_proportion = string.IsNullOrEmpty(request.conv_proportion) ? "" : request.conv_proportion,
                conv_unit = string.IsNullOrEmpty(request.conv_unit) ? "" : request.conv_unit,
                price = request.price > 0 ? request.price : 0,
                min_stock = (int)(request.min_stock > 0 ? request.min_stock : 0),
                max_stock = (int)(request.max_stock > 0 ? request.max_stock : 0),
                is_disable = request.is_disable.ToInt(),
                is_first = request.is_first.ToInt(),
                priority = request.priority ?? "",
                exp = request.exp > 0 ? request.exp : 0,
                desc = request.desc ?? "",
                image = request.image ?? "",
                projectId = ProjectId,
                transdatetime = DateTime.Now,
                category = request.category,
                product_id = request.product_id
            };
            var insertStatus = _materialsRepository.InsertMaterial(entity);
            if (insertStatus > 0)
            {
                if (!string.IsNullOrEmpty(entity.supplier))
                {
                    var ids = entity.supplier.Split(',', StringSplitOptions.RemoveEmptyEntries);
                    foreach (var id in ids)
                    {
                        var IID = id.ToInt();
                        if (IID > 0)
                        {
                            var supplierModel = new SigerTrMaterialSupplier
                            {
                                material_id = entity.id,
                                projectId = ProjectId,
                                status = (int)RowState.Valid,
                                supplier_id = IID
                            };
                            _materialsRepository.InsertSupplier(supplierModel);
                        }
                    }
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult Modify([FromBody] RequestUpdateMaterials request)
        {
            if (request.min_stock < 0 || request.max_stock < 0)
            {
                throw new BadRequestException(RequestEnum.StcokNotLessThanZero);
            }
            var minStock = (int)request.min_stock;
            var maxStock = (int)request.max_stock;
            if (minStock - request.min_stock != 0 || maxStock - request.max_stock != 0)
            {
                throw new BadRequestException(RequestEnum.StockMustBeInteger);
            }
            if ((request.min_stock > 0 || request.max_stock > 0) && request.min_stock > request.max_stock)
            {
                throw new BadRequestException(RequestEnum.MaxMinStockError);
            }
            var entity = _materialsRepository.Get(request.id);
            if (entity == null || entity.status != (int)RowState.Valid)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            if (_materialsRepository.IsExist(t => t.name == request.name && t.spec == request.spec && t.status == (int)RowState.Valid
                && t.projectId == ProjectId && t.id != entity.id))
            {
                throw new BadRequestException(RequestEnum.MaterialNameSpecExist);
            }
            if (request.typeid != entity.typeid && _materialTypeRepository.IsExist(t => t.parentid == request.typeid))
                throw new BadRequestException(RequestEnum.AddMaterialsTypeIdError);

            if (request.is_first == "1" && string.IsNullOrEmpty(request.priority))
                throw new BadRequestException(RequestEnum.PriorityIsEmpty);

            entity.typeid = request.typeid;
            entity.name = request.name;
            entity.spec = request.spec;
            //entity.pn = request.pn;//料号是唯一的且不能修改,物料如果有出入库记录则管理模式不能修改
            entity.supplier = request.supplier ?? "";
            entity.manage_mode = request.manage_mode ?? "";
            entity.unit = request.unit ?? "";
            entity.conv_proportion = string.IsNullOrEmpty(request.conv_proportion) ? "" : request.conv_proportion;
            entity.conv_unit = string.IsNullOrEmpty(request.conv_unit) ? "" : request.conv_unit;
            entity.price = request.price > 0 ? request.price : 0;
            entity.min_stock = (int)(request.min_stock > 0 ? request.min_stock : 0);
            entity.max_stock = (int)(request.max_stock > 0 ? request.max_stock : 0);
            entity.is_disable = request.is_disable.ToInt();
            entity.is_first = request.is_first.ToInt();
            entity.priority = request.priority ?? "";
            entity.exp = request.exp > 0 ? request.exp : 0;
            entity.desc = request.desc ?? "";
            entity.image = request.image ?? "";
            entity.category = request.category;
            entity.product_id = request.product_id;
            _materialsRepository.DeleteSuppliers(entity.id, ProjectId);
            var updateStatus = _materialsRepository.UpdateMaterial(entity);
            if (updateStatus > 0)
            {
                if (!string.IsNullOrEmpty(entity.supplier))
                {
                    var ids = entity.supplier.Split(',', StringSplitOptions.RemoveEmptyEntries);
                    foreach (var id in ids)
                    {
                        var iid = id.ToInt();
                        if (iid > 0)
                        {
                            var supplierModel = new SigerTrMaterialSupplier
                            {
                                material_id = entity.id,
                                projectId = ProjectId,
                                status = (int)RowState.Valid,
                                supplier_id = iid
                            };
                            _materialsRepository.InsertSupplier(supplierModel);
                        }
                    }
                }
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpGet]
        public IActionResult Delete(int id)
        {
            var entity = _materialsRepository.Get(id);
            if (entity == null || entity.status != (int)RowState.Valid)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var productStructures = _sigerTrProduct.Get(t => t.pn == entity.pn && t.status == (int)RowState.Valid && t.projectId == ProjectId);
            if (productStructures != null)
            {
                throw new BadRequestException(RequestEnum.MaterialUseNotDelete);
            }

            entity.status = (int)RowState.Invalid;
            var updateStatus = _materialsRepository.UpdateMaterial(entity);
            if (updateStatus > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpGet]
        public IActionResult ExportAll(string name, string exp, string typeid)
        {
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var exp1 = exp.ToInt();
            var materials = _materialsRepository.GetMaterialList(name, exp1, typeid.ToInt(), ProjectId).ToList();
            if (!materials.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var temporaryFileName = $"物料信息_MaterialsInfo_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            var fileName = Path.Combine(rootDir, temporaryFileName);

            var helper = new EpPlusExcelHelper<MaterialTemplate>();
            try
            {
                var mas = new List<MaterialTemplate>();
                var translateHelper = new TranslateHelper(_projectRepository.GetProjectLanguage(ProjectId) == (int)LanguageType.EN);
                foreach (var pro in materials)
                {
                    var suppliers = _bussineseContactsRepository.GetPnSupplierIds(ProjectId, pro.id).ToList();
                    var material = new MaterialTemplate
                    {
                        name = pro.name,
                        typename = pro.typeid_value,
                        spec = pro.spec,
                        pn = pro.pn,
                        supplier = string.Join(',', suppliers.Select(m => m.title)),
                        manage_mode = _sigerDict.GetDictValue(ProjectId, AccDictCostNoProjectId.managemodel, pro.manage_mode),
                        unit = _sigerDict.GetDictValue(ProjectId, AccDictCost.meterunits, pro.unit),
                        conv_unit = _sigerDict.GetDictValue(ProjectId, AccDictCost.convunits, pro.conv_unit),
                        conv_proportion = pro.conv_proportion,
                        price = pro.price.ToStr(),
                        min_stock = pro.min_stock.ToStr(),
                        max_stock = pro.max_stock.ToStr(),
                        is_disable = pro.is_disable == 1 ? translateHelper.GetTranslateText(TranslateEnEnum.Yes) : translateHelper.GetTranslateText(TranslateEnEnum.No),
                        is_first = pro.is_first == 1 ? translateHelper.GetTranslateText(TranslateEnEnum.Yes) : translateHelper.GetTranslateText(TranslateEnEnum.No),
                        priority = _sigerDict.GetDictValue(ProjectId, AccDictCost.prioritytype, pro.priority),
                        exp = pro.exp,
                        desc = pro.desc,
                        image = pro.image
                    };
                    mas.Add(material);
                }

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

        [HttpGet]
        public IActionResult GetTree()
        {
            var list = _materialTypeRepository.GetMaterialTypeTree(ProjectId);
            var response = new ResponseMaterialTypeChildren(ConvertToTree(list));
            return new ObjectResult(response);
        }

        private IList<MaterialTypeTree> ConvertToTree(IEnumerable<MaterialTypeTree> models)
        {
            var materialTypeDic = new Dictionary<int, MaterialTypeTree>();
            foreach (var item in models)
            {
                materialTypeDic.Add(item.id, item);
            }
            var result = new List<MaterialTypeTree>();
            foreach (var item in materialTypeDic.Values)
            {
                if (item.pid == -1)
                {
                    result.Add(item);
                }
                else
                {
                    if (materialTypeDic.ContainsKey(item.pid))
                    {
                        materialTypeDic[item.pid].AddChildren(item);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 获取WMS供应商列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetSuppliers()
        {
            var suppliers = _bussineseContactsRepository.GetSupplierList(ProjectId);

            return new ObjectResult(suppliers);
        }

        [HttpPost]
        public IActionResult Deletes([FromBody]RequestDeleteEntities request)
        {
            if (request.ids == null || !request.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }

            foreach (var requestId in request.ids)
            {
                var entity = _materialsRepository.Get(requestId);
                if (entity == null || entity.status != (int)RowState.Valid)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }

                var productStructures = _sigerTrProduct.Get(t => t.pn == entity.pn && t.status == (int)RowState.Valid && t.projectId == ProjectId);
                if (productStructures != null)
                {
                    throw new BadRequestException(RequestEnum.MaterialUseNotDelete);
                }

                entity.status = (int)RowState.Invalid;
                _materialsRepository.UpdateMaterial(entity);
            }
            return new ObjectResult(CommonEnum.Succefull);
        }
    }
}
