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

namespace Ewide.Core.Service
{
    /// <summary>
    /// 字典值服务
    /// </summary>
    [ApiDescriptionSettings(Name = "DictData", Order = 100)]
    public class SysDictDataService : ISysDictDataService, IDynamicApiController, ITransient
    {
        private readonly IRepository<SysDictData> _sysDictDataRep;  // 字典类型表仓储 
        private readonly IRepository<SysDictType> _sysDictTypeRep;
        public SysDictDataService(IRepository<SysDictData> sysDictDataRep, IRepository<SysDictType> sysDictTypeRep)
        {
            _sysDictTypeRep = sysDictTypeRep;
            _sysDictDataRep = sysDictDataRep;
        }

        /// <summary>
        /// 分页查询字典值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/page")]
        public async Task<dynamic> QueryDictDataPageList([FromBody] DictDataInput input)
        {
            var code = !string.IsNullOrEmpty(input.Code?.Trim());
            var value = !string.IsNullOrEmpty(input.Value?.Trim());
            var dictDatas = await _sysDictDataRep.DetachedEntities
                                  .Where(u => u.TypeId == input.TypeId)
                                  .Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
                                         (value, u => EF.Functions.Like(u.Value, $"%{input.Value.Trim()}%")))
                                  .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
                                  //.Select(u => u.Adapt<DictDataOutput>())
                                  //  .ToPagedListAsync(input.PageNo, input.PageSize)
                                  .ToPageData<SysDictData, DictDataOutput>(input);
            return XnPageResult<DictDataOutput>.PageResult(dictDatas);
        }

        /// <summary>
        /// 获取某个字典类型下字典值列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("/sysDictData/list")]
        public async Task<dynamic> GetDictDataList([FromQuery] QueryDictDataListInput input)
        {
            return await _sysDictDataRep.DetachedEntities.Where(u => u.TypeId == input.TypeId).Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort).ToListAsync();
        }

        /// <summary>
        /// 增加字典值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/add")]
        public async Task AddDictData(AddDictDataInput input)
        {
            var isExist = await _sysDictDataRep.AnyAsync(u => (u.Code == input.Code || u.Value == input.Value) && u.TypeId == input.TypeId, false);
            if (isExist) throw Oops.Oh(ErrorCode.D3003);
            //datatype 的code 为null 则不能添加
            var dataType = _sysDictTypeRep.Where(s => s.Id == input.TypeId).FirstOrDefault();
            if (string.IsNullOrEmpty(dataType.Code)) throw Oops.Oh("此处类型不能添加数据");

            input.ExtCode = CheckExtCode(input.ExtCode);

            var dictData = input.Adapt<SysDictData>();
            await _sysDictDataRep.InsertAsync(dictData);
        }

        /// <summary>
        /// 删除字典值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/delete")]
        public async Task DeleteDictData(DeleteDictDataInput input)
        {
            var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (dictData == null) throw Oops.Oh(ErrorCode.D3004);

            await dictData.DeleteAsync();
        }
        /// <summary>
        /// 删除字典值 id数组传入
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/deleteBatch")]
        public async Task DeleteDictDataBatch([FromBody] string[] ids)
        {
            var dictDataList = await _sysDictDataRep.Where(s => ids.Contains(s.Id)).ToListAsync();
            if (dictDataList.Count == 0) throw Oops.Oh(ErrorCode.D3004);
            dictDataList.ForEach(s =>
            {
                s.DeleteAsync();
            });
        }
        /// <summary>
        /// 更新字典值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/edit")]
        public async Task UpdateDictData(UpdateDictDataInput input)
        {
            var isExist = await _sysDictDataRep.AnyAsync(u => u.Id == input.Id, false);
            if (!isExist) throw Oops.Oh(ErrorCode.D3004);

            // 排除自己并且判断与其他是否相同
            isExist = await _sysDictDataRep.AnyAsync(u => (u.Value == input.Value || u.Code == input.Code) && u.TypeId == input.TypeId && u.Id != input.Id, false);
            if (isExist) throw Oops.Oh(ErrorCode.D3003);

            input.ExtCode = CheckExtCode(input.ExtCode);

            var dictData = input.Adapt<SysDictData>();
            await _sysDictDataRep.UpdateAsync(dictData, ignoreNullValues: true);
        }

        /// <summary>
        /// 字典值详情
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysDictData/detail")]
        public async Task<dynamic> GetDictData([FromQuery] QueryDictDataInput input)
        {
            return await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id, false);
        }

        /// <summary>
        /// 修改字典值状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysDictData/changeStatus")]
        public async Task ChangeDictDataStatus(UpdateDictDataInput input)
        {
            var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (dictData == null) throw Oops.Oh(ErrorCode.D3004);

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

        /// <summary>
        /// 根据字典类型Id获取字典值集合
        /// </summary>
        /// <param name="dictTypeId"></param>
        /// <returns></returns>
        [NonAction]
        public async Task<dynamic> GetDictDataListByDictTypeId(string dictTypeId)
        {
            return await _sysDictDataRep.DetachedEntities.Where(u => u.SysDictType.Id == dictTypeId)
            .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
            .Select(u => new
            {
                u.Code,
                u.Value,
                ExtCode = String.IsNullOrEmpty(u.ExtCode) ? null : Newtonsoft.Json.JsonConvert.DeserializeObject<object>(u.ExtCode),
                u.Remark
            }).ToListAsync();
        }

        [NonAction]
        public async Task<dynamic> GetDictDataListByDictTypeIds(SysDictType[] dictTypes)
        {
            var dictTypeIds = dictTypes.Select(u => u.Id);
            var dictData = await _sysDictDataRep.DetachedEntities.Where(u => dictTypeIds.Contains(u.SysDictType.Id))
                .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
                .ToListAsync();
            var result = new Dictionary<string, dynamic>();
            foreach (var dictType in dictTypes)
            {
                result.Add(dictType.Code, dictData.Where(u => u.TypeId == dictType.Id)
                    .Select(u => new
                    {
                        u.Code,
                        u.Value,
                        ExtCode = String.IsNullOrEmpty(u.ExtCode) ? null : Newtonsoft.Json.JsonConvert.DeserializeObject<object>(u.ExtCode),
                        u.Remark
                    }));
            }
            return result;
        }

        /// <summary>
        /// 删除字典下所有值
        /// </summary>
        /// <param name="dictTypeId"></param>
        [NonAction]
        public async Task DeleteByTypeId(string dictTypeId)
        {
            var dictDatas = await _sysDictDataRep.Where(u => u.TypeId == dictTypeId).ToListAsync();
            dictDatas.ForEach(u =>
            {
                u.Delete();
            });
        }

        [NonAction]
        private string CheckExtCode(string extCode)
        {
            if (!string.IsNullOrEmpty(extCode))
            {
                try
                {
                    if (extCode.StartsWith('{') && extCode.EndsWith('}'))
                    {
                        return Newtonsoft.Json.JsonConvert.SerializeObject(Newtonsoft.Json.JsonConvert.DeserializeObject(extCode));
                    }
                }
                catch { }
            }

            return null;
        }
    }
}
