using DotNetCore.CAP;
using Hotline.Caching.Interfaces;
using Hotline.Configurations;
using Hotline.File;
using Hotline.FlowEngine;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Settings;
using Hotline.Share.Dtos.Knowledge;
using Hotline.Share.Enums.KnowledgeBase;
using Hotline.Share.Mq;
using Hotline.Share.Tools;
using MapsterMapper;
using Microsoft.AspNetCore.Builder.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using SqlSugar;
using System;
using XF.Domain.Authentications;
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;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IRepository<KnowledgeType> _knowledgeTypeRepository;
        private readonly ISessionContext _sessionContext;
        private readonly IFileRepository _fileRepository;
        private readonly IRepository<KnowledgeApprove> _knowledgeApproveRepository;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;

        public KnowledgeDomainService(IKnowledgeRepository knowledgeRepository,
            IMapper mapper,
            IRepository<KnowledgePv> knowledgePVRepository,
            IKnowledgeWorkFlowRepository knowledgeWorkFlowRepository,
            ICapPublisher capPublisher, ISystemSettingCacheManager systemSettingCacheManager,
            IRepository<KnowledgeType> knowledgeTypeRepository,
            ISessionContext sessionContext,
            IFileRepository fileRepository,
            IRepository<KnowledgeApprove> knowledgeApproveRepository,
            IOptionsSnapshot<AppConfiguration> appOptions)
        {
            _knowledgeRepository = knowledgeRepository;
            _mapper = mapper;
            _knowledgePVRepository = knowledgePVRepository;
            _knowledgeWorkFlowRepository = knowledgeWorkFlowRepository;
            _capPublisher = capPublisher;
            _systemSettingCacheManager = systemSettingCacheManager;
            _knowledgeTypeRepository = knowledgeTypeRepository;
            _sessionContext = sessionContext;
            _fileRepository = fileRepository;
            _knowledgeApproveRepository = knowledgeApproveRepository;
            _appOptions = appOptions;
        }

        /// <summary>
        /// 知识库-查询详情-增加浏览量
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<Knowledge> KnowledgeInfo(string Id, CancellationToken cancellationToken)
        {
            var know = await _knowledgeRepository.Queryable()
                //.Includes(x => x.Workflow, d => d.Steps)
                .Includes(x => x.SourceOrganize)
                .Includes(x => x.KnowledgeTypes)
                .FirstAsync(p => p.Id == Id, cancellationToken);
            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)
        {
            var content = know.Content;
            var length = content.Length;
            double randomInRange = 0;
            Random random = new Random();
            double min = 0.10;
            double max = 0.29;
            randomInRange = min + (max - min) * random.NextDouble();
            var browseTime = Convert.ToInt32((randomInRange * length) / 60);
            if (browseTime <= 1)
            {
                browseTime = random.Next(2, 6);
            }
            //写入浏览记录
            KnowledgePv knowledgePv = new()
            {
                CreationTime = DateTime.Now,
                KnowledgeCode = know.Code,
                KnowledgeId = know.Id,
                BrowseTime = browseTime
            };
            //浏览记录写入
            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.Queryable().Where(x => x.KnowledgeId == workflowExternalId).FirstAsync(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.Queryable().Where(x => x.Id == workflowExternalId).FirstAsync(cancellationToken);
            if (knowledge == null)
                throw new UserFriendlyException($"无效知识编号, knowledgeId: {workflowExternalId}", "无效知识编号");
            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> 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 knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workflow.ExternalId, cancellationToken);
            if (knowledge == null)
                throw new UserFriendlyException($"知识查询失败");

            //修改主表审批状态  根据流程ID查询审批主表
            var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.KnowledgeId == workflow.ExternalId, cancellationToken);
            if (workFlow == null)
                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.ExternalId}", "无效流程编号");

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

            if (workflow.ModuleCode == WorkflowModuleConsts.KnowledgeOffshelf)
            {
                knowledge.Status = EKnowledgeStatus.OnShelf;
                await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
            }
            else
            {
                //现有知识状态更改为已撤回
                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.KnowledgeId == workflow.ExternalId, cancellationToken);
            if (workFlow == null)
                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.ExternalId}", "无效流程编号");

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

            workFlow.HandleTime = DateTime.Now;
            workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Success;
            workFlow.ActualOpinion = workflow.ActualOpinion;
            await _knowledgeWorkFlowRepository.UpdateAsync(workFlow, 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.ExternalId)
                .FirstAsync();

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


            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;
                case WorkflowModuleConsts.KnowledgeOffshelf://下架
                                                            //知识先下架                          
                    knowledge.Status = EKnowledgeStatus.OffShelf;
                    knowledge.OffShelfTime = System.DateTime.Now;
                    knowledge.WorkflowId = workflow.Id;
                    await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                    isSendType = "2";
                    break;
            }

            #region 数据推送
            var pushKnowledge = _mapper.Map<KnowledgeSendDto>(knowledge);
            pushKnowledge.CategoryCode = "01";
            pushKnowledge.CategoryName = "公共服务";

            //高效办成一件事配置
            var cancelPublishOrderEnabled = _systemSettingCacheManager.GetSetting(SettingConstants.EfficientlyAccomplish)?.SettingValue[0];
            //获取到配置，执行下面
            if (!string.IsNullOrEmpty(cancelPublishOrderEnabled))
            {
                var isEfficientlyAccomplish = false;
                //根据知识ID查询所有的知识分类
                //var typeList = await _relationTypeRepository.Queryable().Where(p => p.KnowledgeId == knowledge.Id).ToListAsync(cancellationToken);
                //if (typeList != null && typeList.Any())
                //{
                //    //遍历知识分类
                //    foreach (var item in typeList)
                //    {
                //        //查询知识分类是否满足高效办成一件事
                //        if (await _knowledgeTypeRepository.AnyAsync(p => p.Id == item.KnowledgeTypeId && p.SpliceName.StartsWith(cancelPublishOrderEnabled), cancellationToken))
                //        {
                //            //满足，跳出遍历
                //            isEfficientlyAccomplish = true;
                //            break;
                //        }
                //    }
                //}
                //是高效，处理默认值
                if (isEfficientlyAccomplish)
                {
                    pushKnowledge.CategoryCode = "25";
                    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
        }

        /// <summary>
        /// 知识库-新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<Knowledge> AddKnowledgeAsync(AddKnowledgeDto dto, CancellationToken cancellationToken)
        {
            var kn = _mapper.Map<Knowledge>(dto);
            kn.SourceOrganizeId = _sessionContext.RequiredOrgId;
            var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.OnShelf && x.Title == kn.Title).AnyAsync();
            if (any) throw UserFriendlyException.SameMessage("当前知识标题存在重复标题！");

            //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.Drafts;
            kn.InitId();
            if (dto.Files.NotNullOrEmpty()) kn.FileJson = await _fileRepository.AddFileAsync(dto.Files, kn.Id, "", cancellationToken);

            if (dto.KnowledgeType.Any())
            {
                var knTypes = _mapper.Map<List<KnowledgeType>>(dto.KnowledgeType);
                kn.KnowledgeTypes = knTypes;
            }
            if (dto.KnowledgeOrg.Any())
            {
                kn.KnowledgeOrganizes = dto.KnowledgeOrg.Select(x => new SystemOrganize { Id = x }).ToList();
            }

            await _knowledgeRepository.AddNav(kn)
                .Include(d => d.KnowledgeTypes)
                .Include(d => d.KnowledgeOrganizes)
                .ExecuteCommandAsync();

            return kn;
        }

        /// <summary>
        /// 插入知识审批数据
        /// </summary>
        public async Task<KnowledgeApprove> AddKnowledgeApproveAsync(EKnowledgeApproveType knowledgeApproveType, Knowledge kn, string? createOpinion,
            CancellationToken cancellation)
        {
            var approve = new KnowledgeApprove
            {
                KnowledgeId = kn.Id,
                KnowledgeApproveType = knowledgeApproveType,
                KnowledgeApproveStatus = EKnowledgeApproveStatus.Unhandle,
                CreateOpinion = createOpinion,
            };

            await _knowledgeApproveRepository.AddAsync(approve, cancellation);

            kn.Status = EKnowledgeStatus.Auditing;
            await _knowledgeRepository.UpdateAsync(kn, cancellation);

            return approve;
        }

        public async Task<Knowledge> UpdateKnowledgeAsync(UpdateKnowledgeDto dto, CancellationToken cancellation)
        {
            var knowledge = await _knowledgeRepository.GetAsync(d => d.Id == dto.Id, cancellation);
            if (knowledge == null)
                throw UserFriendlyException.SameMessage("无效知识编号");
            if ((knowledge.Status == EKnowledgeStatus.OnShelf || knowledge.Status == EKnowledgeStatus.Auditing)
                && (knowledge.ExpiredTime.HasValue && knowledge.ExpiredTime.Value > DateTime.Now))
                throw UserFriendlyException.SameMessage("知识库数据不可修改");
            var any = await _knowledgeRepository.Queryable()
                .AnyAsync(x => x.Status == EKnowledgeStatus.OnShelf && x.Title == dto.Title && x.Id != dto.Id, cancellation);
            if (any) throw UserFriendlyException.SameMessage("当前知识标题已存在！");

            _mapper.Map(dto, knowledge);
            if (dto.Files != null && dto.Files.Any())
                knowledge.FileJson = await _fileRepository.AddFileAsync(dto.Files, knowledge.Id, "", cancellation);
            else
                knowledge.FileJson = new List<Share.Dtos.File.FileJson>();
            knowledge.Renewaln = knowledge.Status != EKnowledgeStatus.Drafts;
            if (_appOptions.Value.IsYiBin)
            {
                //临时处理 修改后提交修改基本信息
                if (!_sessionContext.OrgIsCenter)
                {
                    knowledge.Attribution = "部门知识库";
                }
                knowledge.CreatorId = _sessionContext.UserId;
                knowledge.CreatorName = _sessionContext.UserName;
                knowledge.CreatorOrgId = _sessionContext.OrgId;
                knowledge.CreatorOrgName = _sessionContext.OrgName;
                knowledge.CreatorOrgLevel = _sessionContext.OrgLevel;
            }


            if (dto.KnowledgeType != null && dto.KnowledgeType.Any())
            {
                knowledge.KnowledgeTypes = dto.KnowledgeType.Select(x => new KnowledgeType { Id = x.KnowledgeTypeId }).ToList();
            }
            if (dto.KnowledgeOrg != null && dto.KnowledgeOrg.Any())
            {
                knowledge.KnowledgeOrganizes = dto.KnowledgeOrg.Select(x => new SystemOrganize { Id = x }).ToList();
            }

            await _knowledgeRepository.UpdateNav(knowledge)
                .Include(d => d.KnowledgeTypes, new UpdateNavOptions { ManyToManyIsUpdateA = true })
                .Include(d => d.KnowledgeOrganizes, new UpdateNavOptions { ManyToManyIsUpdateA = true })
                .ExecuteCommandAsync();
            //if (dto.KnowledgeType.Any())
            //         {
            //             knowledge.KnowledgeTypes = dto.KnowledgeType.Select(d => new KnowledgeType
            //             {
            //                 Id = d.KnowledgeTypeId,
            //             }).ToList();
            //             await _knowledgeRepository.UpdateNav(knowledge)
            //                 .Include(d => d.KnowledgeTypes, new UpdateNavOptions
            //                 {
            //                     ManyToManyIsUpdateA = true
            //                 })
            //                 .ExecuteCommandAsync();
            //         }
            //         else
            //         {
            //             await _knowledgeRepository.UpdateAsync(knowledge, cancellation);
            //         }




            return knowledge;
        }

        /// <summary>
        /// 下架知识
        /// </summary>
        public async Task<Knowledge> OffShelfAsync(OffShelfKnowledgeDto dto, CancellationToken cancellation)
        {
            var kn = await _knowledgeRepository.Queryable()
                .Includes(d => d.User)
                .Includes(d => d.HotspotType)
                .Includes(d => d.SystemOrganize)
                .FirstAsync(d => d.Id == dto.Id, cancellation);
            if (kn is null) throw new UserFriendlyException("无效知识id");
            if (kn.Status == EKnowledgeStatus.OffShelf) return kn;
            if (kn.Status != EKnowledgeStatus.OnShelf) throw new UserFriendlyException("知识下架失败");

            kn.OffShelf();

            await _knowledgeRepository.UpdateAsync(kn, cancellation);

            var pushKnowledge = _mapper.Map<KnowledgeSendDto>(kn);
            pushKnowledge.CategoryCode = "01";
            pushKnowledge.CategoryName = "公共服务";
            //推省上
            await _capPublisher.PublishAsync(EventNames.HotlineKnowledgeRemove, pushKnowledge, cancellationToken: cancellation);

            return kn;
        }
    }
}