using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
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.Repository.Response;
using Siger.Middlelayer.Utility.Helpers;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.ApiConfig.Controller
{
    public class MaterialTypeController : BaseController
    {
        private readonly ISigerTrMaterialTypeRepository _materialTypeRepository;
        private readonly ISigerTrMaterialsRepository _materialsRepository;
        private readonly IUnitOfWork _unitOfWork;
        public MaterialTypeController(IUnitOfWork unitOfWork, ISigerTrMaterialTypeRepository materialTypeRepository,
            ISigerTrMaterialsRepository materialsRepository)
        {
            _unitOfWork = unitOfWork;
            _materialTypeRepository = materialTypeRepository;
            _materialsRepository = materialsRepository;
        }

        [HttpGet]
        public IActionResult GetList(string name, int page = 1, int pagesize = PageSize)
        {
            var pid = name.ToInt();

            var list = _materialTypeRepository.GetPagedList(pid, ProjectId, page, pagesize);

            var response = new List<ResponseGetMaterialType>();
            foreach (var materialType in list.Data)
            {
                response.Add(new ResponseGetMaterialType
                {
                    id = materialType.id,
                    name = materialType.name,
                    pid_value = materialType.pname,
                    pid = materialType.pid,
                    tcode = materialType.tcode
                });
            }

            return new PagedObjectResult(response, list.Total, page, pagesize);
        }

        [HttpGet]
        public IActionResult GetNameList()
        {
            var response = new List<ResponseIdName>();

            var list = _materialTypeRepository.GetList(q =>q.status == (int)RowState.Valid&&q.projectId==ProjectId);

            foreach (var item in list)
            {
                if (list.First(t => t.parentid == t.id) == null)
                {
                    response.Add(new ResponseIdName
                    {
                        id = item.id,
                        name = item.name
                    });
                }
            }

            return new ObjectResult(response);
        }

        [HttpPost]
        public IActionResult Add([FromBody] RequestAddMaterialType request)
        {
            if (string.IsNullOrWhiteSpace(request.name))
                throw new BadRequestException(RequestEnum.NameIsEmpty);
            if (string.IsNullOrEmpty(request.tcode))
                throw new BadRequestException(RequestEnum.MaterislTypeIsEmpty);
            int parentid = 0;
            if(!string.IsNullOrEmpty(request.pid) && !int.TryParse(request.pid,out parentid))
            {
                throw new BadRequestException(RequestEnum.IdIsEmpty);
            }
            if (!string.IsNullOrEmpty(request.tcode) && !Regex.Match(request.tcode, @"^[a-zA-Z0-9]{2}$").Success)
            {
                throw new BadRequestException(RequestEnum.TcodeTypeError);
            }
            if (_materialTypeRepository.IsExist(t => t.tcode == request.tcode && t.status == (int)RowState.Valid && t.projectId == ProjectId) || request.tcode.ToUpper() == "AL")
            {
                throw new BadRequestException(RequestEnum.TcodeHasExist);
            }
            var isExist = _materialTypeRepository.IsExist(q => q.name == request.name && q.status == (int)RowState.Valid && q.projectId == ProjectId);
            if (isExist)
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }
            var depth = GetMaterialTypeDepth(parentid, ProjectId, 1);
            if (parentid < 0 || depth >= 4)
            {
                throw new BadRequestException(RequestEnum.MaterialTypeLevelError);
            }

            var entity = new siger_tr_material_type
            {
                projectId = ProjectId,
                tcode = request.tcode,
                name = request.name,
                parentid = parentid,
                transdatetime = DateTime.Now
            };
            var insertStatus = _materialTypeRepository.InsertMaterialType(entity);
            if (insertStatus > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

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

            var response = new ResponseGetMaterialType
            {
                id = entity.id,
                name = entity.name,
                tcode = entity.tcode
            };
            if (entity.parentid != 0)
            {
                var parentEntity = _materialTypeRepository.Get(entity.parentid);
                if (parentEntity == null || parentEntity.status != (int)RowState.Valid)
                {
                    throw new BadRequestException(CommonEnum.RecordNotFound);
                }
                response.pid = parentEntity.id;
                response.name = parentEntity.name;
            }

            return new ObjectResult(new List<ResponseGetMaterialType> { response });
        }

        [HttpPost]
        public IActionResult Modify([FromBody] RequestUpdateMaterialType request)
        {
            if (string.IsNullOrWhiteSpace(request.name))
                throw new BadRequestException(RequestEnum.NameIsEmpty);
            var entity = _materialTypeRepository.Get(request.id);
            if (entity == null || entity.status != (int)RowState.Valid)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            if (entity.id.ToStr() == request.pid)
            {
                throw new BadRequestException(RequestEnum.ParentTypeError);
            }
            if (entity.tcode != request.tcode)
            {
                if (!string.IsNullOrEmpty(request.tcode) && !Regex.Match(request.tcode, @"^[a-zA-Z0-9]{2}$").Success)
                {
                    throw new BadRequestException(RequestEnum.TcodeTypeError);
                }
                if (_materialTypeRepository.IsExist(t => t.tcode == request.tcode && t.status == (int)RowState.Valid && t.projectId == ProjectId))
                {
                    throw new BadRequestException(RequestEnum.TcodeHasExist);
                }
            }
            if (entity.name != request.name)
            {
                var isExist = _materialTypeRepository.IsExist(q => q.name == request.name && q.status == (int)RowState.Valid && q.projectId == ProjectId);
                if (isExist)
                {
                    throw new BadRequestException(RequestEnum.NameHasExist);
                }
            }
            var lists = GetSonTypes(request.id);
            if (lists.Select(t => t.id).Contains(request.pid.ToInt()))
            {
                throw new BadRequestException(RequestEnum.ParentTypeError);
            }
            int parentid = 0;
            if (!string.IsNullOrEmpty(request.pid) && !int.TryParse(request.pid, out parentid))
            {
                throw new BadRequestException(RequestEnum.IdIsEmpty);
            }
            var depth = GetMaterialTypeDepth(parentid, ProjectId, 1);
            if (parentid < 0 || depth >= 4)
            {
                throw new BadRequestException(RequestEnum.MaterialTypeLevelError);
            }

            //entity.tcode = request.tcode;
            entity.name = request.name;
            entity.parentid = parentid;
            var updateStatus = _materialTypeRepository.UpdateMaterialType(entity);
            if (updateStatus > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

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

            var lists = GetSonTypes(id);
            lists.Add(entity);
            var deleteList = new List<siger_tr_material_type>();
            foreach (var item in lists)
            {
                var material = _materialsRepository.Get(t => t.typeid == item.id && t.status == (int)RowState.Valid && t.projectId == ProjectId);
                if (material != null)
                {
                    throw new BadRequestException(RequestEnum.MaterialTypeUseNotDelete);
                }

                item.status = (int) RowState.Invalid;
                deleteList.Add(item);
            }

            var updateStatus = _materialTypeRepository.UpdateMaterialTypeRange(deleteList);
            if (updateStatus > 0)
                return new ObjectResult(CommonEnum.Succefull);
            throw new BadRequestException(CommonEnum.Fail);
        }

        private List<siger_tr_material_type> GetSonTypes(int parentId)
        {
            var query = _materialTypeRepository.GetList(t => t.parentid == parentId && t.status == (int)RowState.Valid && t.projectId == ProjectId);

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonTypes(t.id))).ToList();
        }

        /// <summary>
        /// 获取深度-超过4层不能添加
        /// </summary>
        /// <returns></returns>
        private int GetMaterialTypeDepth(int parentid, int projectid, int depth)
        {
            var entity = _materialTypeRepository.Get(t => t.id == parentid && t.projectId == projectid && t.status == (int)RowState.Valid);
            if (entity!= null && entity.parentid > 0)
            {
                depth++;
                return GetMaterialTypeDepth(entity.parentid, projectid, depth);
            }
            else
            {
                return depth;
            }
        }

        /// <summary>
        /// 导出物料类别
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult ExportAll(int pid)
        {
            if (!(pid >= 0))
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);
            var data = _materialTypeRepository.ExportMaterialTypes(pid, ProjectId);
            var materialTypes = data.ToList();
            if (!materialTypes.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var exportData = new List<MaterialTypeList>();
            var index = 1;
            foreach (var item in materialTypes)
            {
                var typeItem = new MaterialTypeList
                {
                    No = index,
                    Name = item.name,
                    ParentType = item.pname,
                    Tcode = item.tcode
                };
                index++;
                exportData.Add(typeItem);
            }

            EpPlusExcelHelper<MaterialTypeList> helper = null;
            try
            {
                helper = new EpPlusExcelHelper<MaterialTypeList>();
                var temporaryFileName = $"物料类别信息_MaterialTypeInfo_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
                helper.GenerateExcel(exportData, Path.Combine(rootDir, temporaryFileName));
                return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
            }
            catch (Exception e)
            {
                Logger.WriteLineError("ExportMaterialType failed, error:" + e);
                throw new BadRequestException(CommonEnum.SystemExcetion);
            }
            finally
            {
                helper?.Dispose();
            }
        }

        /// <summary>
        /// 返回所有最后一层级的物料类别
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetLastLevelType()
        {
            var lists = _materialTypeRepository.GetList(t => t.projectId == ProjectId && t.status == (int)RowState.Valid).ToList();
            var response = new List<MaterialType>();
            foreach(var item in lists)
            {
                if (lists.FirstOrDefault(t => t.parentid == item.id) == null)
                {
                    response.Add(new MaterialType
                    {
                        id = item.id,
                        name = item.name,
                        tcode = item.tcode,
                        pid = item.parentid
                    });
                }
            }
            return new ObjectResult(response);
        }
    }
}
