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

namespace Siger.ApiQMS.Controllers
{
    public class InspectCategoryController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IInspectCategoryRepository _inspectCategory;
        private readonly IInspectUnhealthyRepository _inspectUnhealthy;
        public InspectCategoryController(IUnitOfWork unitOfWork, IInspectCategoryRepository inspectCategory,
            IInspectUnhealthyRepository inspectUnhealthy)
        {
            _unitOfWork = unitOfWork;
            _inspectCategory = inspectCategory;
            _inspectUnhealthy = inspectUnhealthy;
        }

        [HttpGet]
        public IActionResult GetList(string id, int page = PageIndex, int pagesize = PageSize)
        {
            var list = _inspectCategory.GetPagedList(id.ToInt(), ProjectId, page, pagesize);
            return new PagedObjectResult(list.Data, list.Total, page, pagesize);
        }

        [HttpGet]
        public IActionResult GetNameList()
        {
            var list = _inspectCategory.GetSonCategorys(0, ProjectId).ToList();
            return new ObjectResult(list);
        }

        [HttpGet]
        public IActionResult GetUnhealthyNameList(int categoryid)
        {
            var list = _inspectUnhealthy.GetList(t => t.categoryid == categoryid && t.status == (int)RowState.Valid &&
                t.projectid == ProjectId).Select(q => new ResponseIdNameCode
                {
                    id = q.id,
                    name = q.name,
                    code = q.code,
                }).ToList();
            var res = new List<ResponseIdNameCode>();
            foreach(var item in list)
            {
                var strs = item.code.ToArray();
                var sortValue = "";
                foreach(var str in strs)
                {
                    sortValue += GetAscii(str.ToString());
                }
                if(long.TryParse(sortValue, out long outLong))
                {
                    item.sortvalue = outLong;
                }
                else
                {
                    item.sortvalue = long.MaxValue;
                }
            }
            return new ObjectResult(list.OrderBy(t => t.sortvalue).ToList());
        }

        private int GetAscii(string character)
        {
            var asciiEncoding = new ASCIIEncoding();
            return asciiEncoding.GetBytes(character)[0];
        }

        [HttpPost]
        public IActionResult Add([FromBody] RequestAddInspectionCategory request)
        {
            if (string.IsNullOrWhiteSpace(request.name))
                throw new BadRequestException(RequestEnum.NameIsEmpty);
            if (!string.IsNullOrEmpty(request.parentid) && request.parentid != "0")
            {
                var parent = _inspectCategory.Get(t =>
                    t.id == request.parentid.ToInt() && t.projectid == ProjectId && t.status == (int) RowState.Valid);
                if (parent == null)
                {
                    throw new BadRequestException(RequestEnum.ParentTypeError);
                }
            }
            var isExist = _inspectCategory.IsExist(q => q.name == request.name && q.status == (int)RowState.Valid && q.projectid == ProjectId);
            if (isExist)
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }

            var entity = new siger_qms_inspection_unhealthy_category
            {
                projectid = ProjectId,
                name = request.name,
                parentid = request.parentid.ToInt()
            };
            _inspectCategory.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult Modify([FromBody] RequestUpdateInspectionCategory request)
        {
            if (string.IsNullOrWhiteSpace(request.name))
                throw new BadRequestException(RequestEnum.NameIsEmpty);
            var entity = _inspectCategory.Get(request.id);
            if (entity == null || entity.status != (int)RowState.Valid)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            if (entity.id.ToString() == request.parentid)
            {
                throw new BadRequestException(RequestEnum.ParentTypeError);
            }
            if (entity.name != request.name)
            {
                var isExist = _inspectCategory.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.parentid.ToInt()))
            {
                throw new BadRequestException(RequestEnum.ParentTypeError);
            }
            if (!string.IsNullOrEmpty(request.parentid) && request.parentid != "0")
            {
                var parent = _inspectCategory.Get(t =>
                    t.id == request.parentid.ToInt() && t.projectid == ProjectId && t.status == (int)RowState.Valid);
                if (parent == null)
                {
                    throw new BadRequestException(RequestEnum.ParentTypeError);
                }
            }

            entity.name = request.name;
            entity.parentid = request.parentid.ToInt();
            _inspectCategory.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }
        private List<siger_qms_inspection_unhealthy_category> GetSonTypes(int parentId)
        {
            var query = _inspectCategory.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();
        }

        [HttpPost]
        public IActionResult Delete([FromBody]RequestDeleteParameter req)
        {
            if (req.ids == null || !req.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var models = _inspectCategory.GetList(t => req.ids.Contains(t.id) && t.status == (int)RowState.Valid &&
                t.projectid == ProjectId).ToList();
            if (!models.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var entities = new List<siger_qms_inspection_unhealthy_category>();
            foreach(var model in models)
            {                
                var lists = GetSonTypes(model.id);
                entities.Add(model);
                entities.AddRange(lists);
            }

            entities = entities.GroupBy(t => t.id).Select(t => t.FirstOrDefault()).ToList();
            foreach (var entity in entities)
            {
                if(entity == null)
                {
                    continue;
                }
                entity.status = (int)RowState.Invalid;
                _inspectCategory.Update(entity);
            }

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

        [HttpGet]
        public IActionResult GetUnhealthyList(int categoryid, string name, string code, int page = PageIndex, int pagesize = PageSize, int toexcel = 0)
        {
            Expression<Func<siger_qms_inspection_unhealthy, bool>> keyExpression = q =>
                q.status == (int) RowState.Valid && q.projectid == ProjectId;

            Expression<Func<siger_qms_inspection_unhealthy, bool>> categoryExpression = q => true;
            if (categoryid > 0)
            {
                categoryExpression = q => q.categoryid == categoryid;
            }

            Expression<Func<siger_qms_inspection_unhealthy, bool>> nameExpression = q => true;
            if (!string.IsNullOrEmpty(name))
            {
                nameExpression = q => q.name.Contains(name);
            }

            Expression<Func<siger_qms_inspection_unhealthy, bool>> codeExpression = q => true;
            if (!string.IsNullOrEmpty(code))
            {
                codeExpression = q => q.code.Contains(code);
            }

            var predicate = keyExpression.And(categoryExpression).And(nameExpression).And(codeExpression);            

            var res = new List<ResponseGetUnhealthys>();

            if(toexcel == 1)
            {
                var list = _inspectUnhealthy.GetList(predicate, "id");
                var cateIds = list.Select(t => t.categoryid).ToList();
                var categorys = _inspectCategory.GetList(t =>
                    cateIds.Contains(t.id) && t.projectid == ProjectId && t.status == (int)RowState.Valid).ToList();
                foreach (var data in list)
                {
                    var model = Mapper<siger_qms_inspection_unhealthy, ResponseGetUnhealthys>.Map(data);
                    var category = categorys.FirstOrDefault(t => t.id == data.categoryid);
                    model.categoryname = category?.name ?? "";
                    res.Add(model);
                }

                var result = ExportExcel(res);
                return result;
            }
            else
            {
                var dataList = _inspectUnhealthy.GetPagedList(page, pagesize, predicate, "id");
                var cateIds = dataList.Data.Select(t => t.categoryid).ToList();
                var categorys = _inspectCategory.GetList(t =>
                    cateIds.Contains(t.id) && t.projectid == ProjectId && t.status == (int)RowState.Valid).ToList();
                foreach (var data in dataList.Data)
                {
                    var model = Mapper<siger_qms_inspection_unhealthy, ResponseGetUnhealthys>.Map(data);
                    var category = categorys.FirstOrDefault(t => t.id == data.categoryid);
                    model.categoryname = category?.name ?? "";
                    res.Add(model);
                }

                return new PagedObjectResult(res, dataList.Total, page, pagesize);
            }
        }

        private IActionResult ExportExcel(List<ResponseGetUnhealthys> data)
        {
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);

            if (!data.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var dataList = new List<InspectUnhealthyList>();
            var index = 1;
            foreach (var item in data)
            {
                dataList.Add(new InspectUnhealthyList
                {
                    No = index,
                    category = item.categoryname,
                    code = item.code,
                    name = item.name
                });
                index++;
            }
            if (dataList.Any())
            {
                EpPlusExcelHelper<InspectUnhealthyList> helper = null;
                try
                {
                    helper = new EpPlusExcelHelper<InspectUnhealthyList>();
                    var temporaryFileName = $"不良名称定义_InspectUnhealthyList_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
                    helper.GenerateExcel(dataList, Path.Combine(rootDir, temporaryFileName));
                    return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
                }
                catch (Exception e)
                {
                    Logger.WriteLineError("Export Inspect Unhealthy List failed, error:" + e);
                    throw new BadRequestException(RequestEnum.ExportFailed);
                }
                finally
                {
                    helper?.Dispose();
                }
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult AddUnhealthy([FromBody] RequestAddInspectUnhealthy req)
        {
            var category = _inspectCategory.Get(t =>
                t.id == req.categoryid && t.projectid == ProjectId && t.status == (int) RowState.Valid);
            if (category == null)
            {
                throw new BadRequestException(RequestEnum.CategoryNotNull);
            }

            if (string.IsNullOrEmpty(req.code))
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeIsEmpty);
            }

            if (string.IsNullOrEmpty(req.name))
            {
                throw new BadRequestException(RequestEnum.UnhealthyNameIsEmpty);
            }

            if (!Regex.Match(req.code, @"^[a-zA-Z0-9]{5}$").Success)
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeFormatError);
            }

            var nameExsit = _inspectUnhealthy.Get(t =>
                t.categoryid == req.categoryid && t.name == req.name && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if (nameExsit != null)
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }

            var exist = _inspectUnhealthy.Get(t =>
                t.code == req.code && t.projectid == ProjectId && t.status == (int) RowState.Valid);
            if (exist != null)
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeIsExsit);
            }

            var entity = new siger_qms_inspection_unhealthy
            {
                categoryid = req.categoryid,
                code = req.code,
                name = req.name,
                projectid = ProjectId
            };
            _inspectUnhealthy.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult UpdateUnhealthy([FromBody] RequestUpdateInspectUnhealthy req)
        {
            var entity = _inspectUnhealthy.Get(t =>
                t.id == req.id && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var category = _inspectCategory.Get(t =>
                t.id == req.categoryid && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if (category == null)
            {
                throw new BadRequestException(RequestEnum.CategoryNotNull);
            }

            if (string.IsNullOrEmpty(req.code))
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeIsEmpty);
            }

            if (string.IsNullOrEmpty(req.name))
            {
                throw new BadRequestException(RequestEnum.UnhealthyNameIsEmpty);
            }

            if (!Regex.Match(req.code, @"^[a-zA-Z0-9]{5}$").Success)
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeFormatError);
            }

            var nameExsit = _inspectUnhealthy.Get(t => t.id != req.id && 
                t.categoryid == req.categoryid && t.name == req.name && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if (nameExsit != null)
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }

            var exist = _inspectUnhealthy.Get(t =>
                t.code == req.code && t.id != req.id && t.projectid == ProjectId && t.status == (int)RowState.Valid);
            if (exist != null)
            {
                throw new BadRequestException(RequestEnum.UnhealthyCodeIsExsit);
            }

            entity.categoryid = req.categoryid;
            entity.code = req.code;
            entity.name = req.name;
            entity.projectid = ProjectId;
            _inspectUnhealthy.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult DeleteUnhealthy([FromBody]RequestDeleteParameter req)
        {
            if (req.ids == null || !req.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var entities = _inspectUnhealthy.GetList(t =>
                req.ids.Contains(t.id) && t.projectid == ProjectId && t.status == (int)RowState.Valid).ToList();
            if (!entities.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            foreach(var entity in entities)
            {
                entity.status = (int)RowState.Invalid;
                _inspectUnhealthy.Update(entity);
            }

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