using Hotline.Application.Knowledge;
using Hotline.KnowledgeBase;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Settings;
using Hotline.Settings.Hotspots;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Knowledge;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.KnowledgeBase;
using Hotline.Share.Requests;
using Hotline.Tools;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using XF.Domain.Authentications;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Api.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    public class KnowledgeCommonController : BaseController
    {

        #region 注入
        private readonly IRepository<KnowledgeType> _knowledgeTypeRepository;
        private readonly IKnowledgeTypeDomainService _knowledgeTypeDomainService;
        private readonly IRepository<KnowledgeStandard> _knowledgeStandardRepository;
        private readonly IMapper _mapper;
        private readonly ISessionContext _sessionContext;
        private readonly ISystemOrganizeRepository _systemOrganizeRepository;
        private readonly IRepository<Hotspot> _hotspotTypeRepository;
        private readonly IKnowApplication _knowApplication;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="knowledgeTypeRepository"></param>
        /// <param name="knowledgeTypeDomainService"></param>
        /// <param name="knowledgeStandardRepository"></param>
        /// <param name="sessionContext"></param>
        /// <param name="mapper"></param>
        /// <param name="systemOrganizeRepository"></param>
        /// <param name="hotspotTypeRepository"></param>
        /// <param name="knowApplication"></param>
        public KnowledgeCommonController(IRepository<KnowledgeType> knowledgeTypeRepository,
            IKnowledgeTypeDomainService knowledgeTypeDomainService,
            IRepository<KnowledgeStandard> knowledgeStandardRepository,
            ISessionContext sessionContext,
            IMapper mapper,
            ISystemOrganizeRepository systemOrganizeRepository,
            IRepository<Hotspot> hotspotTypeRepository,
             IKnowApplication knowApplication)
        {
            _knowledgeTypeRepository = knowledgeTypeRepository;
            _knowledgeTypeDomainService = knowledgeTypeDomainService;
            _knowledgeStandardRepository = knowledgeStandardRepository;
            _mapper = mapper;
            _sessionContext = sessionContext;
            _systemOrganizeRepository = systemOrganizeRepository;
            _hotspotTypeRepository = hotspotTypeRepository;
            _knowApplication = knowApplication;
        }
        #endregion

        #region 知识分类

        /// <summary>
        ///知识分类- 新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("add")]
        public async Task<string> AddType([FromBody] AddKnowledgeTypeDto dto)
        {
            return await _knowledgeTypeDomainService.AddType(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        ///知识分类- 编辑
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update")]
        public async Task UpdateType([FromBody] UpdateKnowledgeTypeDto dto)
        {
            await _knowledgeTypeDomainService.UpdateType(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识分类-新增、编辑初始化
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="ParentId"></param>
        /// <returns></returns>
        [HttpGet("init")]
        public async Task<KnowledgeTypeDto> InitType(string Id, string ParentId)
        {
            return await _knowledgeTypeDomainService.InitType(Id, ParentId, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识分类-查询详情
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpGet("info/{Id}")]
        public async Task<KnowledgeType> GetType(string Id)
        {
            var types = await _knowledgeTypeRepository.Queryable()
                .Includes(x => x.KnowledgeTypeOrgs)
                .Where(x => x.Id == Id)
                .FirstAsync(HttpContext.RequestAborted);
            if (types is null)
                throw UserFriendlyException.SameMessage("查询失败！");
            return types;
        }

        /// <summary>
        /// 知识分类-删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpDelete("remove")]
        public async Task RemoveType(string Id)
        {
            await _knowledgeTypeDomainService.RemoveType(Id, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识分类-启用、禁用切换
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpPut("changestate")]
        public async Task ChangeStateType(string Id)
        {
            await _knowledgeTypeDomainService.ChangeStateType(Id, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识分类-禁用，并且下架知识
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpPut("changestateandoffshelf")]
        public async Task TypeChangeStateAndOffShelf(string Id)
        {
            await _knowledgeTypeDomainService.ChangeStateTypeAndOffShelf(Id, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 知识分类- 获取层级分类
        /// </summary>
        [HttpGet("treelist")]
        public async Task<List<KnowledgeTypeDto>> GetTreeList(bool? isEnable, string? attribution, EKnowledgeStatus? status)
        {
            var isCenter = _sessionContext.OrgIsCenter;
            var query = _knowledgeTypeRepository.Queryable()
                .WhereIF(isEnable.HasValue, x => x.IsEnable == isEnable);
            if (!isCenter)
                query.Where(x => x.Orgs.Any(s => s.Id == _sessionContext.RequiredOrgId));
            return await query
                 .Select(x => new KnowledgeTypeDto()
                 {
                     Id = x.Id.SelectAll(),
                     //KnowledgeNum = SqlFunc.Subqueryable<KnowledgeRelationType>()
                     //    .LeftJoin<Knowledge>((kr, k) => kr.KnowledgeId == k.Id)
                     //    .Where((kr, k) => kr.KnowledgeTypeSpliceName.StartsWith(x.SpliceName))
                     //    .WhereIF(!string.IsNullOrEmpty(attribution) && !isCenter, (kr, k) => k.Attribution == attribution)
                     //    .DistinctCount(kr => kr.KnowledgeId),
                     KnowledgeNum = SqlFunc.Subqueryable<Knowledge>()
                         .InnerJoin<KnowledgeRelationType>((k, krt) => k.Id == krt.KnowledgeId)
                         .InnerJoin<KnowledgeType>((k, krt, t) => krt.KnowledgeTypeId == t.Id)
                         .Where((k, krt, t) => t.SpliceName.StartsWith(x.SpliceName) && k.IsDeleted == false && t.IsDeleted == false)
                         .WhereIF(!string.IsNullOrEmpty(attribution) && !isCenter, (k, krt, t) => k.Attribution == attribution)
                         .WhereIF(status != null, k => k.Status == status)
                         .DistinctCount(k => k.Id)
                 })
                 .OrderBy(x => x.Sort)
                 .ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
        }

        //[HttpGet("treelist")]
        //public async Task<List<KnowledgeTypeDto>> GetTreeList(bool? IsEnable, string? Attribution)
        //{
        //    return await _knowledgeTypeRepository.Queryable()
        //        .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
        //        .Where(x => SqlFunc.Subqueryable<KnowledgeTypeOrg>().Where(to => to.TypeId == x.Id && to.OrgId == _sessionContext.RequiredOrgId).Any()
        //                    || SqlFunc.Subqueryable<KnowledgeTypeOrg>().Where(to => to.TypeId == x.Id).NotAny())
        //        .Select(x => new KnowledgeTypeDto()
        //        {
        //            Id = x.Id.SelectAll(),
        //            KnowledgeNum = SqlFunc.Subqueryable<KnowledgeRelationType>().LeftJoin<Knowledge>((kr, k) => kr.KnowledgeId == k.Id)
        //                .Where((kr, k) => kr.KnowledgeTypeSpliceName.StartsWith(x.SpliceName))
        //                .WhereIF(!string.IsNullOrEmpty(Attribution), (kr, k) => k.Attribution == Attribution).DistinctCount(kr => kr.KnowledgeId)

        //        })
        //        .OrderBy(x => x.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
        //}

        /// <summary>
        /// 知识部门
        /// </summary>
        /// <param name="IsEnable">不传查询所有</param>
        /// <returns></returns>
        [HttpGet("treelist/org")]
        public async Task<List<KnowledgeOrgDto>> GetTreeList(string? Attribution)
        {

            //await Db.Queryable<SystemOrganize>()
            // .Where(it => it.Id.StartsWith(orgCode))
            // .OrderBy(d => d.Id)
            // .ToTreeAsync(it => it.Children, it => it.ParentId, orgCode.Length > 6 ? orgCode.Substring(0, orgCode.Length - 3) : null);
            var orgCode = _sessionContext.RequiredOrgId;
            var query = _systemOrganizeRepository.Queryable().WhereIF(!_sessionContext.OrgIsCenter, it => it.Id.StartsWith(_sessionContext.RequiredOrgId))
                    .Select(it => new KnowledgeOrgDto()
                    {
                        Id = it.Id.SelectAll(),
                        KnowledgeNum = SqlFunc.Subqueryable<Knowledge>()
                            .Where(k => k.CreatorOrgId.StartsWith(it.Id))
                            .WhereIF(!string.IsNullOrEmpty(Attribution), k => k.Attribution == Attribution).DistinctCount(k => k.Id)

                    }).OrderBy(d => d.Id);

            if (_sessionContext.OrgIsCenter)
            {
                return await query.ToTreeAsync(x => x.Children, it => it.ParentId, null);
            }
            return await query.ToTreeAsync(it => it.Children, it => it.ParentId, orgCode.Length > 6 ? orgCode.Substring(0, orgCode.Length - 3) : null);

        }

        /// <summary>
        /// 查询子项
        /// </summary>
        [HttpGet("treelist/hotspot")]
        public async Task<IReadOnlyList<KnowledgeHotSpotDto>> GetChildren([FromQuery] string? id, string? Attribution)
        {
            var list = await _hotspotTypeRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(id), x => x.ParentId == id)
                .WhereIF(string.IsNullOrEmpty(id), x => x.ParentId == null || x.ParentId == "")
                .OrderBy(d => d.HotSpotName)
                .Select(x => new KnowledgeHotSpotDto
                {
                    Id = x.Id.SelectAll(),
                    HasChild = SqlFunc.Subqueryable<Hotspot>().Where(d => d.ParentId == x.Id).NotAny(),
                    KnowledgeNum = SqlFunc.Subqueryable<Knowledge>().LeftJoin<Hotspot>((k, h) => k.HotspotId == h.Id)
                        .Where((k, h) => h.HotSpotFullName.StartsWith(x.HotSpotFullName))
                        .WhereIF(!string.IsNullOrEmpty(Attribution), (k, h) => k.Attribution == Attribution).DistinctCount(k => k.Id)
                }).ToListAsync();

            return list;
        }


        /// <summary>
        /// 名称检索热点树形
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet("treelist/children-hasname")]
        public async Task<IReadOnlyList<KnowledgeHotSpotDto>> GetChildrenHasName([FromQuery] string Name, string? Attribution)
        {
            var arr = _hotspotTypeRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(Name), x => x.HotSpotFullName.Contains(Name)).Select(x => x.Id).ToList().Cast<object>().ToArray();
            //.ToTreeAsync(x => x.Children, it => it.ParentId, null);
            return await _hotspotTypeRepository.Queryable().Select(x => new KnowledgeHotSpotDto
            {
                Id = x.Id.SelectAll(),
                HasChild = SqlFunc.Subqueryable<Hotspot>().Where(d => d.ParentId == x.Id).NotAny(),
                KnowledgeNum = SqlFunc.Subqueryable<Knowledge>().LeftJoin<Hotspot>((k, h) => k.HotspotId == h.Id)
                    .Where((k, h) => h.HotSpotFullName.StartsWith(x.HotSpotFullName))
                    .WhereIF(!string.IsNullOrEmpty(Attribution), (k, h) => k.Attribution == Attribution).DistinctCount(k => k.Id)
            }).ToTreeAsync(x => x.Children, it => it.ParentId, "", arr);
        }


        /// <summary>
        /// 知识分类- 只获取一级
        /// </summary>
        /// <param name="ParentId">不传默认查询第一级</param>
        /// <param name="IsEnable">不传查询所有，包含已经禁用的</param>
        /// <returns></returns>
        [HttpGet("typelist")]
        public async Task<List<KnowledgeType>> GetTypeList(string? ParentId, bool? IsEnable)
        {
            return await _knowledgeTypeRepository
                .Queryable()
                .Where(p => p.ParentId == ParentId)
                .WhereIF(IsEnable.HasValue, p => p.IsEnable == IsEnable)
                .OrderByDescending(p => p.Sort)
                .ToListAsync();
        }

        #endregion

        #region 编写规范

        /// <summary>
        /// 编写规范-查询详情
        /// </summary>
        /// <returns></returns>
        [HttpGet("info-standard")]
        public async Task<KnowledgeStandard> GetStandard()
        {
            var sandard = await _knowledgeStandardRepository.Queryable().FirstAsync();
            if (sandard == null)
            {
                KnowledgeStandard standard = new()
                {
                    Title = "",
                    Content = ""
                };
                var Id = await _knowledgeStandardRepository.AddAsync(standard, HttpContext.RequestAborted);
                return await _knowledgeStandardRepository.GetAsync(Id, HttpContext.RequestAborted);
            }
            return sandard;
        }

        /// <summary>
        /// 编写规范-修改
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update-standard")]
        public async Task UpdateStandard([FromBody] UpdateKnowledgeStandardDto dto)
        {
            var standard = await _knowledgeStandardRepository.GetAsync(dto.Id);
            _mapper.Map(dto, standard);
            await _knowledgeStandardRepository.UpdateAsync(standard, HttpContext.RequestAborted);
        }
        #endregion

        #region 知识超期未更新统计
        /// <summary>
        /// 知识超期未更新统计
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("get-know-overdue-statistics-list")]
        public async Task<PagedDto<KnowedgeStatisticsDto>> GetKnowOverdueStatisticsList([FromQuery] PagedKeywordRequest dto)
        {
            var (total, items) = await _knowApplication.GetKnowedgeStatistics(dto)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<KnowedgeStatisticsDto>(total, items);
        }

        /// <summary>
        ///知识超期未更新统计导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("get-know-overdue-statistics-list-export")]
        public async Task<FileStreamResult> GetKnowOverdueStatisticsListExport([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
        {
            var query = _knowApplication.GetKnowedgeStatistics(dto.QueryDto);
            List<KnowedgeStatisticsDto> data;
            if (dto.IsExportAll)
            {
                data = await query.ToListAsync(HttpContext.RequestAborted);
            }
            else
            {
                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                data = items;
            }

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<KnowedgeStatisticsDto>(dto.ColumnInfos);

            var dtos = data
                .Select(stu => _mapper.Map(stu, typeof(KnowedgeStatisticsDto), dynamicClass))
                .Cast<object>()
                .ToList();

            var stream = ExcelHelper.CreateStream(dtos);

            return ExcelStreamResult(stream, "知识超期未更新统计");
        }
        #endregion
    }
}
