using DotNetCore.CAP;
using Hotline.FlowEngine;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Share.Dtos.Knowledge;
using Hotline.Share.Enums.KnowledgeBase;
using Hotline.Share.Mq;
using MapsterMapper;
using SqlSugar;
using XF.Domain.Dependency;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.KnowledgeBase
{
    public class KnowledgeDomainService : IKnowledgeDomainService, IScopeDependency
    {
        private readonly IKnowledgeRepository _knowledgeRepository;
        private readonly IMapper _mapper;
        private readonly IRepository<KnowledgePv> _knowledgePVRepository;
        private readonly IKnowledgeWorkFlowRepository _knowledgeWorkFlowRepository;
        private readonly ICapPublisher _capPublisher;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="knowledgeRepository"></param>
        /// <param name="mapper"></param>
        /// <param name="knowledgePVRepository"></param>
        /// <param name="knowledgeWorkFlowRepository"></param>
        /// <param name="capPublisher"></param>
        public KnowledgeDomainService(IKnowledgeRepository knowledgeRepository, IMapper mapper, IRepository<KnowledgePv> knowledgePVRepository
            , IKnowledgeWorkFlowRepository knowledgeWorkFlowRepository, ICapPublisher capPublisher)
        {
            _knowledgeRepository = knowledgeRepository;
            _mapper = mapper;
            _knowledgePVRepository = knowledgePVRepository;
            _knowledgeWorkFlowRepository = knowledgeWorkFlowRepository;
            _capPublisher = capPublisher;
        }

        /// <summary>
        /// 知识库-查询详情-增加浏览量
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<Knowledge> KnowledgeInfo(string Id, CancellationToken cancellationToken)
        {
            var know = await _knowledgeRepository.Queryable(false, false, false)
                .Includes(x => x.Workflow, d => d.Steps)
                .Includes(x=>x.SourceOrganize)
                .Includes(x=>x.KnowledgeType).FirstAsync(p => p.Id == Id);
            if (know is null)
                throw UserFriendlyException.SameMessage("知识查询失败！");
            return know;
        }

        /// <summary>
        /// 浏览记录写入
        /// </summary>
        /// <param name="know"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task KnowledgePvIncreaseAsync(Knowledge know, CancellationToken cancellationToken)
        {
            //写入浏览记录
            KnowledgePv knowledgePv = new()
            {
                CreationTime = DateTime.Now,
                KnowledgeCode = know.Code
            };
            //浏览记录写入
            await _knowledgePVRepository.AddAsync(knowledgePv, cancellationToken);

            //修改浏览量
            know.PageView++;
            //修改点击量
            await _knowledgeRepository.UpdateAsync(know, cancellationToken);
        }

        /// <summary>
        /// 知识审批主表
        /// </summary>
        /// <param name="knowId">知识Id</param>
        /// <param name="eKnowledgeApplyType">申请类型</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<string> AddWorkFlowAsync(string knowId, EKnowledgeApplyType eKnowledgeApplyType, CancellationToken cancellationToken)
        {
            KnowledgeWorkFlow workFlow = new()
            {
                KnowledgeId = knowId,
                WorkflowModuleStatus = eKnowledgeApplyType,
                WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Auditing,
            };
            return await _knowledgeWorkFlowRepository.AddAsync(workFlow, cancellationToken);
        }

        /// <summary>
        /// 修改流程ID
        /// </summary>
        public async Task UpdateWorkFlowId(string workflowExternalId, string workflowId, List<HandlerGroupItem> handlerUsers, List<HandlerGroupItem> handlerOrgs,
            List<string> flowedUserIds, List<string> flowedOrgIds, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(workflowExternalId))
                throw UserFriendlyException.SameMessage("无效知识编号");
            var knowledgeFlow =
                await _knowledgeWorkFlowRepository.GetAsync(workflowExternalId, cancellationToken);
            if (knowledgeFlow == null)
                throw new UserFriendlyException($"无效知识编号, knowledgeFlowId: {workflowExternalId}", "无效知识编号");
            knowledgeFlow.WorkflowId = workflowId;
            knowledgeFlow.Flowed(flowedUserIds, flowedOrgIds, handlerUsers, handlerOrgs);
            await _knowledgeWorkFlowRepository.UpdateAsync(knowledgeFlow, cancellationToken);
            var knowledge = await _knowledgeRepository.GetAsync(knowledgeFlow.KnowledgeId, cancellationToken);
            if (knowledge == null)
                throw new UserFriendlyException($"无效知识编号, knowledgeId: {knowledgeFlow.KnowledgeId}", "无效知识编号");
            knowledge.WorkflowId = workflowId;
            knowledge.Status = EKnowledgeStatus.Auditing;
            knowledge.Flowed(flowedUserIds, flowedOrgIds, handlerUsers, handlerOrgs);
            await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
        }
        
        /// <summary>
        /// 修改指派人
        /// </summary>
        /// <param name="assignInfo"></param>
        /// <param name="knowledgeFlowId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task UpdateWorkAssign(FlowAssignInfo assignInfo, string? knowledgeFlowId, CancellationToken cancellationToken)
        {
            //知识流程表
            var knowledgeFlow =
                await _knowledgeWorkFlowRepository.GetAsync(knowledgeFlowId, cancellationToken);
            if (knowledgeFlow == null)
                throw new UserFriendlyException($"无效知识编号, knowledgeFlowId: {knowledgeFlowId}", "指派失败");

            knowledgeFlow.Assign(assignInfo.FlowAssignType, assignInfo.GetHandlerIds());
            await _knowledgeWorkFlowRepository.UpdateAsync(knowledgeFlow, cancellationToken);

            //知识主表
            var knowledge = await _knowledgeRepository.GetAsync(p => p.WorkflowId == knowledgeFlow.WorkflowId, cancellationToken);
            if (knowledge != null)
            {
                knowledge.Assign(assignInfo.FlowAssignType, assignInfo.GetHandlerIds());
                await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
            }
        }

        /// <summary>
        /// 知识库-新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<string> KnowledgeAdd(AddKnowledgeDto dto, CancellationToken cancellationToken)
        {
            var kn = _mapper.Map<Knowledge>(dto);

            //Code为空，从新生成Code
            if (string.IsNullOrEmpty(kn.Code))
                kn.Code = Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds).ToString();

            kn.Status = EKnowledgeStatus.Auditing;
            return await _knowledgeRepository.AddAsync(kn, cancellationToken);

        }

        /// <summary>
        /// 知识库-修改
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<string> KnowledgeUpdate(UpdateKnowledgeDto dto, CancellationToken cancellationToken)
        {
            //知识修改逻辑
            //如果可以修改，此条数据不动，重新写入一条新数据，知识编号不变，版本号+1，审批通过以后在数据交换

            var know = await _knowledgeRepository.GetAsync(dto.Id, cancellationToken);
            if (know is null || know.IsDeleted)
                throw UserFriendlyException.SameMessage("无效知识");
            //审批中数据不能处理
            if (know.Status == EKnowledgeStatus.Auditing)
                throw UserFriendlyException.SameMessage("审批中数据不能修改");

            var knowledge = _mapper.Map<Knowledge>(dto);
            knowledge.Code = know.Code;
            knowledge.PageView = know.PageView;
            knowledge.Status = EKnowledgeStatus.Auditing;
            knowledge.Id = null;
            knowledge.Version = 0;

            return await _knowledgeRepository.AddAsync(knowledge, cancellationToken);

        }

        /// <summary>
        /// 流程终止，处理知识状态
        /// </summary>
        /// <param name="workflow"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="UserFriendlyException"></exception>
        public async Task TerminateWorkKnowledge(Workflow workflow, CancellationToken cancellationToken)
        {
            //修改主表审批状态  根据流程ID查询审批主表
            var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.WorkflowId == workflow.Id, cancellationToken);
            if (workFlow == null)
                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.Id}", "无效流程编号");

            //根据审批主表知识ID查询当前知识
            var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workFlow.KnowledgeId, cancellationToken);
            if (knowledge == null)
                throw new UserFriendlyException($"知识查询失败");

            //修改业务数据状态
            workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Revoke;
            workFlow.ActualOpinion = workflow.ActualOpinion;
            await _knowledgeWorkFlowRepository.UpdateAsync(workFlow);

            //现有知识状态更改为已撤回
            knowledge.Status = EKnowledgeStatus.Revert;
            await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);

			//switch (workFlow.WorkflowModuleStatus)
   //         {
   //             case EKnowledgeApplyType.Add:
   //                 //将知识保存为草稿
   //                 knowledge.Status = EKnowledgeStatus.Drafts;
   //                 await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
   //                 break;
   //             default:
   //                 //现有知识状态更改为已撤回
   //                 knowledge.Status = EKnowledgeStatus.Revert;
   //                 await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
   //                 break;

                   
			//}
        }

        /// <summary>
        /// 流程审批完成，处理知识状态
        /// </summary>
        /// <param name="workflow"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="UserFriendlyException"></exception>
        public async Task EndWorkKnowledge(Workflow workflow, CancellationToken cancellationToken)
        {
            //修改主表审批状态  根据流程ID查询审批主表
            var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.WorkflowId == workflow.Id, cancellationToken);
            if (workFlow == null)
                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.Id}", "无效流程编号");

            //根据审批主表知识ID查询当前知识
            //  var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workFlow.KnowledgeId, cancellationToken);

            var knowledge = await _knowledgeRepository.Queryable(false, false, false)
                .Includes(it => it.SystemOrganize)
                .Includes(it => it.HotspotType)
                .Includes(it => it.User)
                .Where(p => p.Id == workFlow.KnowledgeId)
                .FirstAsync();

            if (knowledge == null)
                throw new UserFriendlyException($"知识查询失败");

            workFlow.HandleTime = DateTime.Now;
            workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Success;
            workFlow.ActualOpinion = workflow.ActualOpinion;
			await _knowledgeWorkFlowRepository.UpdateAsync(workFlow, cancellationToken);

            string isSendType = "";//推送类别：新增0，修改1，删除2

            switch (workflow.ModuleCode)
            {
                case WorkflowModuleConsts.KnowledgeAdd://新增
                case WorkflowModuleConsts.KnowledgeUpdate://修改
                                                          //根据Code查询是否有历史数据
                    var oldKnowledge = await _knowledgeRepository
                       .Queryable()
                       .Where(p => p.Code == knowledge.Code && (p.Status == EKnowledgeStatus.OnShelf || p.Status == EKnowledgeStatus.OffShelf)
                                        && p.IsDeleted == false && p.Id != knowledge.Id)
                       .OrderByDescending(p => p.Version)
                       .Take(1)
                       .FirstAsync();
                    if (!knowledge.Renewaln.Value)
                    {
                        isSendType = "0";
                    }
                    else
                    {
                        isSendType = "1";
                    }

                    //修改知识状态为已上架
                    knowledge.Status = EKnowledgeStatus.OnShelf;
                    knowledge.OnShelfTime = System.DateTime.Now;

                    await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                    break;

                case WorkflowModuleConsts.KnowledgeDelete://删除
                    //知识先下架，在删除                                       
                    knowledge.Status = EKnowledgeStatus.OffShelf;
                    knowledge.OffShelfTime = System.DateTime.Now;
                    knowledge.WorkflowId = workflow.Id;
                    await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                    //删除知识
                    await _knowledgeRepository.RemoveAsync(p => p.Code == knowledge.Code, true, cancellationToken);

                    isSendType = "2";
                    break;
            }

            #region 数据推送
            var pushKnowledge = _mapper.Map<KnowledgeSendDto>(knowledge);
            pushKnowledge.CategoryCode = "01";
            pushKnowledge.CategoryName = "公共服务";
			//推送
			if (isSendType == "0")  //新增知识推送

                await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeAdd, pushKnowledge, cancellationToken: cancellationToken);
            else if (isSendType == "1")  //修改知识推送

                await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeUpdate, pushKnowledge, cancellationToken: cancellationToken);
            else if (isSendType == "2")   //删除知识推送

                await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeRemove, pushKnowledge, cancellationToken: cancellationToken);
            #endregion
        }
    }
}