using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Ewide.Core.Service
{
    /// <summary>
    /// 字典类型服务
    /// </summary>
    [ApiDescriptionSettings(Name = "DictType", Order = 100)]
    public class SysDictTypeService : ISysDictTypeService, IDynamicApiController, ITransient
    {
        private readonly IRepository<SysDictType> _sysDictTypeRep;  // 字典类型表仓储   
        private readonly ISysDictDataService _sysDictDataService;

        public SysDictTypeService(ISysDictDataService sysDictDataService,
                                  IRepository<SysDictType> sysDictTypeRep)
        {
            _sysDictDataService = sysDictDataService;
            _sysDictTypeRep = sysDictTypeRep;
        }

        /// <summary>
        /// 分页查询字典类型
        /// </summary>
        /// <returns></returns>
        [HttpPost("/sysDictType/page")]
        public async Task<dynamic> QueryDictTypePageList([FromBody] DictTypeInput input)
        {
            var code = !string.IsNullOrEmpty(input.Code?.Trim());
            var name = !string.IsNullOrEmpty(input.Name?.Trim());
            var pId = !string.IsNullOrEmpty(input.Pid?.Trim());
            var type = input.Type > 0;
            var dictTypes = await _sysDictTypeRep.DetachedEntities
                                  .Where(pId, u => EF.Functions.Like(u.Pids, $"%[{input.Pid.Trim()}]%") || u.Id == input.Pid.Trim())
                                  .Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
                                         (name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
                                  .Where(type, u => input.Type == 1 ? string.IsNullOrEmpty(u.Code) : !string.IsNullOrEmpty(u.Code))
                                  .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
                                  //.ToPagedListAsync(input.PageNo, input.PageSize);
                                  .ToPageData(input);
            return XnPageResult<SysDictType>.PageResult(dictTypes);
        }

        /// <summary>
        /// 获取字典类型列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("/sysDictType/list")]
        public async Task<dynamic> GetDictTypeList()
        {
            return await _sysDictTypeRep.DetachedEntities.Where(u => u.Status != CommonStatus.DELETED).ToListAsync();
        }

        /// <summary>
        /// 获取字典类型下所有字典值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysDictType/dropDown")]
        public async Task<dynamic> GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input)
        {
            var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Code == input.Code, false);
            if (dictType == null) throw Oops.Oh(ErrorCode.D3000);
            return await _sysDictDataService.GetDictDataListByDictTypeId(dictType.Id);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysDictType/dropDowns")]
        public async Task<dynamic> GetDictTypeDropDowns([FromQuery] DropDownDictTypesInput input)
        {
            var dictTypes = await _sysDictTypeRep.Where(u => input.Code.Contains(u.Code), false).ToArrayAsync();
            if (dictTypes.Length == 0) throw Oops.Oh(ErrorCode.D3000);
            return await _sysDictDataService.GetDictDataListByDictTypeIds(dictTypes);
        }

        /// <summary>
        /// 添加字典类型
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictType/add")]
        public async Task AddDictType(AddDictTypeInput input)
        {
            var isExist = await _sysDictTypeRep.AnyAsync(u => u.Name == input.Name, false);
            if (isExist) throw Oops.Oh(ErrorCode.D3001);
            var dictTypeEntity = _sysDictTypeRep.Where(s => s.Pid == input.Pid).FirstOrDefault();
            if (dictTypeEntity != null && dictTypeEntity.Code != null) throw new Exception("此类型下不能添加子类型");
            var dictType = input.Adapt<SysDictType>();
            dictType.Pids = await CreateNewPids(input.Pid);
            if (input.Code == string.Empty) dictType.Code = null;
            await _sysDictTypeRep.InsertAsync(dictType);
        }

        /// <summary>
        /// 删除字典类型
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictType/delete")]
        public async Task DeleteDictType(DeleteDictTypeInput input)
        {
            var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (dictType == null) throw Oops.Oh(ErrorCode.D3000);

            var dictDatas = await _sysDictDataService.GetDictDataListByDictTypeId(input.Id); //_sysDictDataService.DeleteByTypeId(input.Id);
            if (dictDatas != null && dictDatas.Count > 0) throw Oops.Oh(ErrorCode.D3002);

            await dictType.DeleteAsync();
        }

        /// <summary>
        /// 更新字典类型
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictType/edit"),]
        public async Task UpdateDictType(UpdateDictTypeInput input)
        {
            if (input.Id == input.Pid) throw Oops.Oh(ErrorCode.D4006);
            var result = _sysDictTypeRep.Where(u => u.Id == input.Id).Select(s => new { s.Name, s.Id, s.Code }).ToList().First();
            if (result == null) throw Oops.Oh(ErrorCode.D3000);
            if (result.Name == input.Name) throw Oops.Oh(ErrorCode.D3001);
            // 如果是编辑，父id不能为自己的子节点
            //var childIdList = await _sysDictTypeRep.DetachedEntities.Where(u => u.Pids.Contains(input.Id.ToString()))
            //                                                    .Select(u => u.Id).ToListAsync();
            //if (childIdList.Contains(input.Pid)) throw Oops.Oh(ErrorCode.D4006);

            var dictType = input.Adapt<SysDictType>();
            dictType.Pids = await CreateNewPids(input.Pid);
            dictType.Code = input.Code == string.Empty ? null : input.Code;
            await dictType.UpdateIncludeAsync(new string[] { nameof(SysDictType.Pid), nameof(SysDictType.Pids), nameof(SysDictType.Name), nameof(SysDictType.Code), nameof(SysDictType.Sort), nameof(SysDictType.Remark) }, false);
        }

        /// <summary>
        /// 字典类型详情
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysDictType/detail")]
        public async Task<dynamic> GetDictType([FromQuery] QueryDictTypeInfoInput input)
        {
            return await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id, false);
        }

        /// <summary>
        /// 更新字典类型状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictType/changeStatus")]
        public async Task ChangeDictTypeStatus(UpdateDictTypeInput input)
        {
            var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (dictType == null) throw Oops.Oh(ErrorCode.D3000);

            if (!Enum.IsDefined(typeof(CommonStatus), input.Status))
                throw Oops.Oh(ErrorCode.D3005);
            dictType.Status = input.Status;
        }

        /// <summary>
        /// 字典类型与字典值构造的字典树
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("/sysDictType/tree")]
        public async Task<List<DictTreeNode>> GetDictTree()
        {
            var DictTypeList = await _sysDictTypeRep.AsQueryable().Where(p => string.IsNullOrEmpty(p.Code)).ToListAsync();
            return new TreeBuildUtil<DictTreeNode>().DoTreeBuild(DictTypeList
                .OrderBy(s => s.Sort)
                .Select(u => new DictTreeNode
                {
                    Title = u.Name,
                    ParentId = u.Pid,
                    Id = u.Id,
                    Value = u.Id
                }).ToList());
        }
        /// <summary>
        /// 创建Pids格式 
        /// 如果pid是0顶级节点，pids就是 [0];
        /// 如果pid不是顶级节点，pids就是 pid菜单的 pids + [pid] + ,
        /// </summary>
        /// <param name="pid"></param>
        /// <returns></returns>
        private async Task<string> CreateNewPids(string pid)
        {
            if (pid.Equals(System.Guid.Empty.ToString()))
            {
                return "[" + System.Guid.Empty + "],";
            }
            else
            {
                var dtype = await _sysDictTypeRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == pid);
                return dtype.Pids + "[" + pid + "],";
            }
        }
    }
}
