using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiIMS.Result;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.FieldEnum;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Response;
using Siger.Middlelayer.IMSRepository.Entities;
using Siger.Middlelayer.IMSRepository.Repositories.Interface;
using Siger.Middlelayer.IMSRepository.Request;
using Siger.Middlelayer.IMSRepository.Response;

namespace Siger.ApiIMS.Controllers
{
    public class CategoryController: BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IToolLifeCategoryRepository _categoryRepository;
        private readonly ISigerProjectParameterRepository _parameterRepository;
        private readonly ISigerProjectParameterExtendRepository _extendRepository;
        private readonly IToolLifeCategoryPrameterRepository _categoryPrameterRepository;
        public CategoryController(IUnitOfWork unitOfWork, IToolLifeCategoryRepository categoryRepository, 
            IToolLifeCategoryPrameterRepository categoryPrameterRepository,
            ISigerProjectParameterRepository parameterRepository,
            ISigerProjectParameterExtendRepository extendRepository)
        {
            _unitOfWork = unitOfWork;
            _categoryRepository = categoryRepository;
            _categoryPrameterRepository = categoryPrameterRepository;
            _extendRepository = extendRepository;
            _parameterRepository = parameterRepository;
        }

        [HttpGet]
        public IActionResult GetCategoryTree(int type, string keyword)
        {
            var categories = _categoryRepository.GetAllCategories(ProjectId, (ImsSettingCategory)type).ToList();
            var entities = new List<ToolCategoryTree>();

            if (!string.IsNullOrWhiteSpace(keyword))
            {
                var cateGories = categories.Where(t => t.name.Contains(keyword));
                foreach (var category in cateGories)
                {
                    var cates = GetParentCategories(category.parent, categories).ToList();
                    if (category.name.Contains(keyword))
                    {
                        cates.Add(category);
                    }
                    foreach(var cate in cates)
                    {
                        entities.Add(new ToolCategoryTree
                        {
                            id = cate.id,
                            pid = cate.parent,
                            name = cate.name,
                            code = cate.code,
                            title = cate.name
                        });
                    }
                }
                entities = entities.GroupBy(t => t.id).Select(t => t.FirstOrDefault()).ToList();
            }
            else
            {
                foreach (var category in categories)
                {
                    entities.Add(new ToolCategoryTree
                    {
                        id = category.id,
                        pid = category.parent,
                        name = category.name,
                        code = category.code,
                        title = category.name
                    });
                }
            }

            return new ObjectResult(ConvertToTreeForTpm(entities, type));
        }
        private IEnumerable<siger_project_ims_category> GetParentCategories(int parentId, IEnumerable<siger_project_ims_category> categories)
        {
            var query = categories.Where(t => t.id == parentId);

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentCategories(t.parent, categories)));
        }

        private ToolCategoryTree ConvertToTreeForTpm(IEnumerable<ToolCategoryTree> models, int type)
        {
            var section = new Dictionary<int, ToolCategoryTree>();
            foreach (var item in models)
            {
                section.Add(item.id, item);
            }
            var types = EnumHelper.EnumToList<ImsSettingCategory>();
            var name = types.FirstOrDefault(f => f.EnumValue == type)?.Description + "类型";
            
            var result = new ToolCategoryTree
            {
                id = 0,
                pid = 0,
                code = "",
                name = name, //刀柄类型，附件类型
                title = name
            };
            var response = new List<ToolCategoryTree>();
            foreach (var item in section.Values)
            {
                if (item.pid == 0)
                {
                    response.Add(item);
                }
                else
                {
                    if (section.ContainsKey(item.pid))
                    {
                        section[item.pid].AddChilrden(item);
                    }
                }
            }

            result.children = response;
            return result;
        }

        [HttpPost]
        public IActionResult Add([FromBody]RequestAddCategory request)
        {
            var isExist = _categoryRepository.GetList(q => q.name == request.name &&  (int)q.categorys == request.type &&
                                                       q.project_id == ProjectId && q.status == (int) RowState.Valid);
            if (isExist.Any())
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }
            var codeExist = _categoryRepository.GetList(q => q.code == request.code && (int)q.categorys == request.type &&
                                                           q.project_id == ProjectId && q.status == (int)RowState.Valid);
            if (codeExist.Any())
            {
                throw new BadRequestException(RequestEnum.CategoryCodeIsExist);
            }

            var entity = new siger_project_ims_category
            {
                project_id = ProjectId,
                categorys = (ImsSettingCategory)request.type,
                code = request.code,
                name = request.name,
                parent = request.parent.ToInt()
            };
            _categoryRepository.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult Edit([FromBody]RequestUpdateCategory request)
        {
            var isExist = _categoryRepository.GetList(q => q.name == request.name && (int)q.categorys == request.type &&
                                                           q.project_id == ProjectId && q.status == (int)RowState.Valid && q.id != request.id);
            if (isExist.Any())
            {
                throw new BadRequestException(RequestEnum.NameHasExist);
            }
            var codeExist = _categoryRepository.GetList(q => q.code == request.code && (int)q.categorys == request.type &&
                                                             q.project_id == ProjectId && q.status == (int)RowState.Valid && q.id != request.id);
            if (codeExist.Any())
            {
                throw new BadRequestException(RequestEnum.CategoryCodeIsExist);
            }

            var entity = _categoryRepository.Get(q =>
                q.id == request.id && q.categorys == (ImsSettingCategory) request.type &&
                q.status == (int) RowState.Valid);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            entity.code = request.code;
            entity.name = request.name;
            _categoryRepository.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult Delete(int id)
        {
            var entity = _categoryRepository.Get(q =>
                q.id == id && q.status == (int)RowState.Valid && q.project_id == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            entity.status = (int) RowState.Invalid;
            _categoryRepository.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpGet]
        public IActionResult GetCategory(int id)
        {
            var entity = _categoryRepository.Get(q => q.id == id && q.status == (int)RowState.Valid && q.project_id == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var categoryParameters =
                _categoryPrameterRepository.GetList(
                    q => q.category_id == entity.id && q.status == (int) RowState.Valid).ToList();

            var response = new ResponseGetCategoryItem
            {
                code = entity.code,
                name = entity.name,
                GeometryParameter = GetParamters(ParameterCategory.Geometry, categoryParameters),
                TechnologyParameter = GetParamters(ParameterCategory.Technology, categoryParameters),
            };

            return new ObjectResult(response);
        }

        private List<ResponseGetParameterList> GetParamters(ParameterCategory category, List<siger_project_ims_category_parameter> parameters)
        {
            var ids = parameters.Where(q => q.parameter_category == category.ToString()).Select(m => m.parameter_id);

            var result = new List<ResponseGetParameterList>();
            var paras = _parameterRepository.GetList(q => ids.Contains(q.id) &&
                q.category == category.ToString() && q.status == (int)RowState.Valid
                                                                    && (q.module == Module.IMS.ToString().ToLower() ||
                                                                    q.module == $"{Module.IMS.ToString().ToLower()}s") &&
                                                                    q.project_id == ProjectId).ToList();
            foreach (var para in paras)
            {
                var parameter = new ResponseGetParameterList
                {
                    code = para.code,
                    name = para.name,
                    unit = para.unit,
                    id = para.id,
                    type = para.type
                };
                if (parameter.type == 2)
                {
                    parameter.code = GetParameterCode(parameter.id);
                }
                result.Add(parameter);
            }

            return result;
        }

        private string GetParameterCode(int paraId)
        {
            var extends = _extendRepository.GetList(q =>
                q.parameter_id == paraId && q.project_id == ProjectId &&
                q.status == (int)RowState.Valid);
            if (extends.Any())
            {
                return string.Join(',', extends.ToList().Select(m => m.value));
            }

            return string.Empty;
        }

        [HttpPost]
        public IActionResult UpdateCategoryParameters([FromBody] RequestUpdateCategoryParameter request)
        {
            var entity = _categoryRepository.Get(q =>
                q.id == request.id && q.status == (int)RowState.Valid && q.project_id == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            var hasParameters = _categoryPrameterRepository.GetList(q =>
                q.project_id == ProjectId && q.category_id == entity.id
                                          && q.parameter_category == request.category);
            foreach (var hasParameter in hasParameters.ToList())
            {
                _categoryPrameterRepository.Delete(hasParameter);
            }
            if (request.parameters != null && request.parameters.Any())
            {
                foreach (var parameter in request.parameters)
                {
                    var para = new siger_project_ims_category_parameter
                    {
                        category_id = request.id,
                        parameter_id = parameter,
                        project_id = ProjectId,
                        parameter_category = request.category
                    };
                    _categoryPrameterRepository.Insert(para);
                }
            }
            
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }
    }
}