using Ewide.Core.Extension;
using Ewide.Core.Service.Area.Dto;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Ewide.Core.Service.Area
{
    public class AreaCodeService : IAreaCodeService, ITransient
    {
        private readonly IRepository<SysAreaCode> _areaCodeRep;
        private readonly IRepository<SysOrg> _sysOrgRep;
        private readonly ISysCacheService _sysCacheService;

        public AreaCodeService(IRepository<SysAreaCode> AreaCodeRep, ISysCacheService sysCacheService, IRepository<SysOrg> sysOrgRep)
        {
            _areaCodeRep = AreaCodeRep;
            _sysCacheService = sysCacheService;
            _sysOrgRep = sysOrgRep;
        }
        /// <summary>
        /// 添加一个区域
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task AddAreaCode(AreaCodeInput input)
        {
            CheckInput(input);
            CheckCode(input);
            CheckArea(input);
            await _areaCodeRep.InsertNowAsync(input.Adapt<SysAreaCode>());
            await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
        }
        /// <summary>
        /// 删除一个区域
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task DeleteAreaCode(DeleteAreaCodeInput input)
        {
            var AreaCode = await _areaCodeRep.FirstOrDefaultAsync(p => p.Code == input.Code);
            if (await _sysOrgRep.DetachedEntities.AnyAsync(o => o.AreaCode == input.Code))
            {
                throw Oops.Oh("不能删除已包含区域的组织");
            }
            await AreaCode.DeleteNowAsync();
            await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
        }
        /// <summary>
        /// 根据区域代码获取区域信息
        /// </summary>
        /// <param name="code">区域代码</param>
        /// <returns></returns>
        public async Task<SysAreaCode> GetAreaCode(string code)
        {
            var cachedAreaCodes = await _sysCacheService.GetAreaCode();
            if (cachedAreaCodes == null || cachedAreaCodes.Count < 0)
            {
                cachedAreaCodes = await _areaCodeRep.DetachedEntities.ToListAsync();
                await _sysCacheService.SetAreaCode(cachedAreaCodes);
            }
            return cachedAreaCodes.FirstOrDefault(a => a.Code == code);
        }
        /// <summary>
        /// 获取区域目录树
        /// </summary>
        /// <returns></returns>
        public async Task<List<AreaTreeNode>> GetAreaCodeTree()
        {
            var cachedAreaCodes = await _sysCacheService.GetAreaCode();
            if (cachedAreaCodes == null || cachedAreaCodes.Count < 0)
            {
                cachedAreaCodes = await _areaCodeRep.DetachedEntities.ToListAsync();
                await _sysCacheService.SetAreaCode(cachedAreaCodes);
            }
            return new TreeBuildUtil<AreaTreeNode>().DoTreeBuild(cachedAreaCodes.Select(u => new AreaTreeNode
            {
                Code = u.Code,
                AdCode = u.AdCode,
                ParentCode = u.ParentCode,
                Name = u.Name,
                LevelType = u.LevelType,
                Note = u.Note
            }).ToList());
        }

        public async Task<List<SysAreaCode>> GetAreaCodeWithChildren(string code)
        {
            return await _areaCodeRep.DetachedEntities.Where(a => a.Code.StartsWith(code)).ToListAsync();
        }

        public async Task<dynamic> QueryAreaCodePageList(AreaCodeInput input)
        {
            var AreaCodes = await _areaCodeRep.DetachedEntities
                .Where(input.LevelType.HasValue, a => a.LevelType == input.LevelType)
                .Where(!string.IsNullOrEmpty(input.Code), a => a.Code.StartsWith(input.Code))
                .Where(!string.IsNullOrEmpty(input.AdCode), a => a.AdCode.StartsWith(input.AdCode))
                .Where(!string.IsNullOrEmpty(input.Name), a => a.Name.StartsWith(input.Name))
                .ToPageData(input);
            return XnPageResult<SysAreaCode>.PageResult(AreaCodes);
        }

        /// <summary>
        /// 更新区域信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateAreaCode(AreaCodeInput input)
        {
            CheckInput(input);
            CheckArea(input);
            var area = input.Adapt<SysAreaCode>();
            await area.UpdateNowAsync();
            await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
        }
        private bool CheckInput(AreaCodeInput input)
        {
            //检查level和区域长度
            if (false)
            {
                throw Oops.Oh("数据异常");
            }
            //检查是否有子节点
            return true;
        }

        private bool CheckArea(AreaCodeInput input)
        {
            var any = _areaCodeRep.DetachedEntities.Any(p => p.AdCode == input.AdCode && p.Code != input.Code);
            if (any)
            {
                throw Oops.Oh("区域编码重复");
            }
            return true;
        }

        private bool CheckCode(AreaCodeInput input)
        {
            var any = _areaCodeRep.DetachedEntities.Any(p =>  p.Code == input.Code);
            if (any)
            {
                throw Oops.Oh("编码重复");
            }
            return true;
        }
    }
}
