using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Mapster;
using Microsoft.EntityFrameworkCore;
using YGNT.Infrastructure.Helper;
using YGNT.Infrastructure.Model;
using YGNT.QuestionLibrary.Core.EducationCategories;
using YGNT.QuestionLibrary.Core.IRepositories;
using YGNT.QuestionLibrary.Core.KnowledgePoints;
using YGNT.QuestionLibrary.Core.KnowledgePoints.Cache;
using YGNT.QuestionLibrary.Core.KnowledgePoints.Domain;
using YGNT.QuestionLibrary.Core.Models;
using YGNT.QuestionLibrary.KnowledgePoints.Dto;

namespace YGNT.QuestionLibrary.KnowledgePoints
{
    /// <summary>
    /// 知识点
    /// </summary>
    public class KnowledgePointAppService : IKnowledgePointAppService
    {
        private readonly IKnowledgePointRepository _knowledgePointRepository;
        private readonly IKnowledgePointTreePathManager _treePathManager;
        private readonly IKnowledgePointManager _knowledgePointManager;
        private readonly IKnowledgePointCache _knowledgePointCache;
        private readonly IRepository<KnowledgePoint, long> _knowledgePointRepository2;
        private readonly IHttpHelper _httpHelper;
        private readonly IRepository<EducationCategory> _educationCategoryRepository;
        private readonly IDisciplineRepository _disciplineRepository;

        public KnowledgePointAppService(IKnowledgePointRepository knowledgePointRepository, 
            IKnowledgePointTreePathManager treePathManager, 
            IKnowledgePointManager knowledgePointManager, 
            IKnowledgePointCache knowledgePointCache, 
            IRepository<KnowledgePoint, long> knowledgePointRepository2,
            IHttpHelper httpHelper,
            IRepository<EducationCategory> educationCategoryRepository,
            IDisciplineRepository disciplineRepository)
        {
            _knowledgePointRepository = knowledgePointRepository;
            _treePathManager = treePathManager;
            _knowledgePointManager = knowledgePointManager;
            _knowledgePointCache = knowledgePointCache;
            _knowledgePointRepository2 = knowledgePointRepository2;
            _httpHelper = httpHelper;
            _educationCategoryRepository = educationCategoryRepository;
            _disciplineRepository = disciplineRepository;
        }

        /// <summary>
        /// 查询知识点列表
        /// </summary>
        /// <param name="search"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<KnowledgeTreePointDto>> GetListAsync(SearchKnowledgePointInputDto search)
        {
            var queryable = _knowledgePointRepository.GetAll()
                .WhereIf(!search.DisciplineId.HasValue, x => x.Discipline.Grade.EducationCategory.IsActive)
                .WhereIf(!search.KeyWord.IsNullOrEmpty(), x => x.Name.Contains(search.KeyWord))
                .WhereIf(search.CognitiveAbilityId.HasValue, x => x.CognitiveAbilityId == search.CognitiveAbilityId)
                .WhereIf(search.DisciplineId.HasValue, x => x.DisciplineId == search.DisciplineId)
                .Where(x => x.ParentId == search.ParentId)
                .OrderBy(x => x.Sort)
                .ThenBy(x => x.Name);
            var result = new PagedResultDto<KnowledgeTreePointDto>()
            {
                TotalCount = await queryable.CountAsync(),
                Items = await queryable.PageBy(search.SkipCount, search.MaxResultCount)
                    .Select(x => x.Adapt(new KnowledgeTreePointDto()
                    {
                        CognitiveAbility = x.CognitiveAbility.Name,
                        Discipline = x.Discipline.Name,
                        HasChild = x.ChildKnowledgePoints.Any()
                    }))
                    .ToListAsync()
            };
            foreach (var knowledgeTreePointDto in result.Items)
            {
                knowledgeTreePointDto.Path = await _treePathManager.GetNamePathAsync(knowledgeTreePointDto.Id);
            }
            return result;
        }

        /// <summary>
        /// 查询知识点详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<KnowledgeTreePointDto> GetOneAsync([Required] long id)
        {
            var knowledgeTree = await _knowledgePointRepository.GetAll()
                .Where(x => x.Id == id)
                .Select(x => x.Adapt(new KnowledgeTreePointDto()
                {
                    CognitiveAbility = x.CognitiveAbility.Name,
                    Discipline = x.Discipline.Name,
                    HasChild = x.ChildKnowledgePoints.Any(),
                }))
                .FirstOrDefaultAsync();
            knowledgeTree.Path = await _treePathManager.GetNamePathAsync(id);
            return knowledgeTree;
        }

        /// <summary>
        /// 获取所有的子知识点(包括自己)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<List<KnowledgePointDto>> GetAllChildKnowledgePointAsync([Required] long id)
        {
            var treePaths = await _treePathManager.GetDescendantAsync(id);
            return await _knowledgePointRepository.GetAll()
                .Where(x => treePaths.Select(s => s.Descendant).Contains(x.Id))
                .Select(x => x.Adapt<KnowledgePointDto>())
                .ToListAsync();
        }

        /// <summary>
        /// 获取知识点名称路径
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<string> GetNamePathAsync([Required] long id)
        {
            return await _treePathManager.GetNamePathAsync(id);
        }

        /// <summary>
        /// 获取学科下的所有知识点
        /// </summary>
        /// <param name="disciplineId">学科id</param>
        /// <returns></returns>
        public async Task<List<KnowledgePointDisciplineAllDto>> GetKnowledgePointDisciplineAllAsync([Required] long disciplineId)
        {
            var chapter = await _knowledgePointRepository2.GetAll()
                .Where(x => x.DisciplineId == disciplineId)
                .OrderBy(x => x.ParentId).ThenBy(x => x.Sort)
                .Select(x => x.Adapt(new KnowledgePointDisciplineAllDto()))
                .ToListAsync();
            return chapter;
        }

        /// <summary>
        /// 获取所有可用知识点
        /// </summary>
        /// <returns></returns>
        public async Task<List<GetKnowledgePointAllDto>> GetAllAsync()
        {
            var chapter = await _knowledgePointRepository2.GetAll()
                .OrderBy(x => x.DisciplineId).ThenBy(x => x.ParentId).ThenBy(x => x.Sort)
                .Select(x => x.Adapt(new GetKnowledgePointAllDto()))
                .ToListAsync();
            return chapter;
        }

        /// <summary>
        /// 创建新知识点
        /// </summary>
        /// <param name="create"></param>
        /// <returns></returns>
        public async Task<long> CreateAsync(CreateKnowledgePointDto create)
        {
            var knowledgePoint = create.Adapt<KnowledgePoint>();
            await _knowledgePointManager.CheckNameAsync(knowledgePoint.Name, knowledgePoint.ParentId);
            if (create.ParentId.HasValue)
            {
                var parentCacheItem = await _knowledgePointCache.GetAsync(create.ParentId ?? default);
                if (parentCacheItem == null) throw new UserFriendlyException("父知识点的id不存在!");
                if (parentCacheItem.DisciplineId != create.DisciplineId)
                    throw new UserFriendlyException("父知识点所属学科和当前知识点学科不匹配!");
            }

            var lastSort = await _knowledgePointRepository.Query(s => s
                   .Where(x => x.ParentId == knowledgePoint.ParentId)
                   .Select(x => x.Sort)
                   .OrderByDescending(x => x)
                   .FirstOrDefaultAsync());
            knowledgePoint.Sort = lastSort + 1;
            return await _knowledgePointRepository.InsertAndGetIdAsync(knowledgePoint);
        }

        /// <summary>
        /// 修改知识点
        /// </summary>
        /// <param name="id"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public async Task UpdateAsync([Required] long id, UpdateKnowledgePointDto update)
        {
            var knowledgePoint = await _knowledgePointRepository.GetAsync(id);
            update.Adapt(knowledgePoint);
            await _knowledgePointManager.CheckNameAsync(knowledgePoint.Name, knowledgePoint.ParentId);
        }

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="sort"></param>
        /// <returns></returns>
        public async Task Sort(SortDto<long> sort)
        {
            var knowledgePoint = await _knowledgePointRepository.GetAsync(sort.Id);
            KnowledgePoint target = null;
            switch (sort.SortType)
            {
                case SortType.上移:
                    target = await _knowledgePointRepository.Query(s => s
                        .Where(x => x.Sort < knowledgePoint.Sort)
                        .OrderByDescending(x => x.Sort)
                        .FirstOrDefaultAsync());
                    break;
                case SortType.下移:
                    target = await _knowledgePointRepository.Query(s => s
                        .Where(x => x.Sort > knowledgePoint.Sort)
                        .OrderBy(x => x.Sort)
                        .FirstOrDefaultAsync());
                    break;
            }
            if (target == null)
                return;
            var oldSort = target.Sort;
            target.Sort = target.Sort;
            knowledgePoint.Sort = oldSort;
        }

        /// <summary>
        /// 移动知识点节点
        /// </summary>
        /// <param name="id">要移动的知识点Id</param>
        /// <param name="targetParentId">目标知识点(父节点)</param>
        /// <returns></returns>
        public async Task MoveTo([Required] long id, [Required] long targetParentId)
        {
            var knowledgePoint = await _knowledgePointRepository.GetAsync(id);
            var target = await _knowledgePointRepository.GetAsync(targetParentId);
            await _knowledgePointManager.MoveToAsync(knowledgePoint, target);
        }


        /// <summary>
        /// 删除知识点
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteAsync([Required] long id)
        {
            var hasChild = await _knowledgePointRepository.GetAll()
                    .AnyAsync(x => x.ParentId == id);
            if (hasChild) throw new UserFriendlyException("禁止删除有子节点的知识点");
            await _knowledgePointRepository.DeleteAsync(id);
        }

        /// <summary>
        /// 同步知识点
        /// </summary>
        /// <returns></returns>
        public async Task DataSyncAsync()
        {

            #region 查询年有学段

            var educationCategoryList = await _educationCategoryRepository.GetAll().ToListAsync();
            #endregion

            #region 查询所有学课

            var disciplineList = await _disciplineRepository.GetAll().ToListAsync();

            var disciplineGroup = disciplineList.GroupBy(i => i.CourseId);
            #endregion

            foreach(var educationCategory in educationCategoryList)
            {
                foreach(var courseGroup in disciplineGroup)
                {
                    HttpResult httpResult = await _httpHelper.GetAsync($"{AppSettings.App("App", "SyncAddress")}/v1/knowledge/find/tree?learning_period_id={educationCategory.Id}&course_id={courseGroup.Key}");
                    if (httpResult.Success)
                    {
                        var list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<KnowledgeSyncDto>>(httpResult.Data.ToString());
                        if (list != null && list.Count > 0)
                        {
                            foreach (var item in list)
                            {
                                //await DataSyncAsync(item, courseGroup);
                            }
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
            }
        }

        private async Task DataSyncAsync(KnowledgeSyncDto item, IGrouping<int, Core.Disciplines.Discipline> courseGroup)
        {
            foreach (var course in courseGroup)
            {

                KnowledgePoint knowledgePoint = await _knowledgePointRepository.FirstOrDefaultAsync(i => i.KnowledgeId == item.id && i.DisciplineId == course.Id);

                if (knowledgePoint == null)
                {
                    knowledgePoint = new KnowledgePoint();
                }

                knowledgePoint.Name = item.name;
                //ParentId = item.parent_id,
                knowledgePoint.DisciplineId = course.Id;
                knowledgePoint.KnowledgeId = item.id;
                knowledgePoint.Sort = item.sort;


                if (item.parent_id > 0)
                {
                    var knowledgePointParent = await _knowledgePointRepository.FirstOrDefaultAsync(i => i.KnowledgeId == item.parent_id && i.DisciplineId == course.Id);
                    if (knowledgePointParent == null)
                    {
                        continue;
                    }
                    knowledgePoint.ParentId = knowledgePointParent.Id;
                }
                if (knowledgePoint.Id > 0)
                {
                    await _knowledgePointRepository.UpdateAsync(knowledgePoint);
                }
                else
                {
                    await _knowledgePointRepository.InsertAndGetIdAsync(knowledgePoint);
                }
            }
            if (item.children != null)
            {
                foreach (var citem in item.children)
                {
                    await DataSyncAsync(citem, courseGroup);
                }
            }
        }
    }
}