using Hotline.FlowEngine.Workflows;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order.OrderDelay;
using Hotline.Share.Enums.FlowEngine;
using MapsterMapper;
using Microsoft.AspNetCore.Http;
using System.Threading;
using Hotline.Authentications;
using Hotline.BatchTask;
using Hotline.Orders;
using Hotline.Share.Dtos.BatchTask;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.BatchTask;
using Hotline.Share.Enums.Order;
using SqlSugar;
using XF.Domain.Authentications;
using XF.Domain.Dependency;
using XF.Domain.Entities;
using XF.Domain.Exceptions;

namespace Hotline.Application.OrderApp.OrderDelayApp;

public class OrderDelayApplication : IOrderDelayApplication, IScopeDependency
{
    private readonly IOrderDomainService _orderDomainService;
    private readonly IOrderDelayRepository _orderDelayRepository;
    private readonly IWorkflowDomainService _workflowDomainService;
    private readonly IApptaskDomainService _apptaskDomainService;
    private readonly ISessionContext _sessionContext;
    private readonly IMapper _mapper;

    public OrderDelayApplication(
        IOrderDomainService orderDomainService,
        IOrderDelayRepository orderDelayRepository,
        IWorkflowDomainService workflowDomainService,
        IApptaskDomainService apptaskDomainService,
        ISessionContext sessionContext,
        IMapper mapper)
    {
        _orderDomainService = orderDomainService;
        _orderDelayRepository = orderDelayRepository;
        _workflowDomainService = workflowDomainService;
        _apptaskDomainService = apptaskDomainService;
        _sessionContext = sessionContext;
        _mapper = mapper;
    }

    /// <summary>
    /// 查询延期待审批列表
    /// </summary>
    /// <returns></returns>
    public ISugarQueryable<OrderDelay> QueryWaited(DelayListDto dto)
    {
        var isAdmin = _orderDomainService.IsCheckAdmin();
        var hasHandled = dto.IsApply.HasValue && dto.IsApply.Value;
        var query = _orderDelayRepository.Queryable()
            .Includes(d => d.WorkflowSteps.Where(step =>
                    ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                      step.HandlerId == _sessionContext.RequiredUserId) ||
                     (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
                      step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
                     (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                      _sessionContext.Roles.Contains(step.RoleId)) ||
                     (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
                      _sessionContext.Roles.Contains(step.RoleId)
                      && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId)))
                .OrderByDescending(step => step.CreationTime)
                .Take(1)
                .ToList()
            );

        if (!isAdmin)
        {
            if (hasHandled)
            {
                query.Where(d => d.WorkflowSteps
                    .Any(step =>
                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                          step.HandlerId == _sessionContext.RequiredUserId) ||
                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
                          step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                          _sessionContext.Roles.Contains(step.RoleId)) ||
                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
                          _sessionContext.Roles.Contains(step.RoleId)
                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
                        && step.Status == EWorkflowStepStatus.Handled));
            }
            else
            {
                query.Where(d => d.WorkflowSteps
                    .Any(step =>
                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                          step.HandlerId == _sessionContext.RequiredUserId) ||
                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
                          step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                          _sessionContext.Roles.Contains(step.RoleId)) ||
                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
                          _sessionContext.Roles.Contains(step.RoleId)
                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
                        && step.Status < EWorkflowStepStatus.Handled));
            }
        }


        query.Includes(d => d.Order)
            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
            .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Order.No.Contains(dto.No)) //工单编号
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, d => d.Order.IsProvince == true) //是否省工单
            .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == false, d => d.Order.IsProvince == false)
            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Order.Title.Contains(dto.Title)) //工单标题
            .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.Order.SourceChannelCode == dto.Channel) //来源渠道
            .WhereIF(dto.CreationTimeStart.HasValue, d => d.Order.CreationTime >= dto.CreationTimeStart) //受理时间Start
            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.Order.CreationTime <= dto.CreationTimeEnd) //受理时间End
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.Order.AcceptorName == dto.AcceptorName!) //受理人
            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot),
                d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
            .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.Order.AcceptTypeCode == dto.AcceptTypeCode) //受理类型
            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.Order.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
            .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), d => d.Order.CurrentHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
            .WhereIF(dto.CurrentHandleTimeStart.HasValue, d => d.Order.CurrentHandleTime >= dto.CurrentHandleTimeStart) //接办时间Start
            .WhereIF(dto.CurrentHandleTimeEnd.HasValue, d => d.Order.CurrentHandleTime <= dto.CurrentHandleTimeEnd) //接办时间End
            .WhereIF(dto.ApplyTimeStart.HasValue, d => d.CreationTime >= dto.ApplyTimeStart) //延期申请时间Start
            .WhereIF(dto.ApplyTimeEnd.HasValue, d => d.CreationTime <= dto.ApplyTimeEnd) //延期申请时间End
            .WhereIF(!string.IsNullOrEmpty(dto.ApplyName), d => d.CreatorName.Contains(dto.ApplyName)) //延期申请人
            .WhereIF(!string.IsNullOrEmpty(dto.ApplyOrgName), d => d.CreatorOrgName.Contains(dto.ApplyOrgName)) //延期申请部门
            .WhereIF(dto.DelayNum.HasValue, d => d.DelayNum == dto.DelayNum) //延期申请时限
            .WhereIF(dto.DelayUnit.HasValue, d => d.DelayUnit == dto.DelayUnit) //延期申请单位
            .WhereIF(!string.IsNullOrEmpty(dto.DelayReason), d => d.DelayReason.Contains(dto.DelayReason)) //申请理由
            .WhereIF(dto.BeforeDelayStart.HasValue, d => d.BeforeDelay >= dto.BeforeDelayStart) //申请前期满时间Start
            .WhereIF(dto.BeforeDelayEnd.HasValue, d => d.BeforeDelay <= dto.BeforeDelayEnd) //申请前期满时间End
            .OrderByDescending(d => d.ApplyDelayTime)
            ;

        return query;
    }

    /// <summary>
    /// 延期审核
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellation"></param>
    /// <returns></returns>
    public async Task ReviewAsync(OrderDelayReviewRequest request, CancellationToken cancellation)
    {
        /*
         * 查询delay
         * 查询workflow
         * 查询当前节点（待受理or待办理）
         * 查询nextStep（_workflowApplication.GetNextStepsAsync）
         * 非省工单删除省审批节点
         *!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审"删除中心终审
         * 从nextStep中查找与dto传入的nextStepName相同的节点,workflow.NextStepCode = step.Key;workflow.NextStepName = step.Value;
         * 通过：nextAsync，不同意：rejectAsync
         * endhandler:
         *  1.更新orderDelay.DelayState
         *  2.审批通过：
         *      a.更新工单办理期满时间（_orderApplication.DelayOrderExpiredTimeAsync）
         *      b.更新工单未办理节点的期满时间（_workflowDomainService.UpdateUnhandleExpiredTimeAsync）
         *      c.cap publish EventNames.HotlineOrderExpiredTimeUpdate
         */

        request.NextWorkflow.ReviewResult = request.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
        if (request.IsPass)
        {
            await _workflowDomainService.NextAsync(request.NextWorkflow, cancellationToken: cancellation);
        }
        else
        {
            var reject = _mapper.Map<RejectDto>(request.NextWorkflow);
            await _workflowDomainService.RejectAsync(reject, cancellation);
        }
    }

    /// <summary>
    /// 延期批量审核
    /// </summary>
    /// <returns></returns>
    public async Task BatchReviewAsync(BatchOrderDelayReviewRequest request, CancellationToken cancellation)
    {
        var delayIds = request.DelayWithStepIds.Select(d => d.DelayId).Distinct().ToList();
        var delays = await _orderDelayRepository.Queryable()
            .Where(d => delayIds.Contains(d.Id))
            .ToListAsync(cancellation);

        var apptaskItems = new List<AddApptaskItemRequest>();
        var req = new OrderDelayReviewWithSessionRequest
        {
            SessionContext = CreateFakeSessionContext(_sessionContext),//(FakeSessionContext)_sessionContext,
            IsPass = request.IsPass,
            NextWorkflow = request.NextWorkflow
        };
        foreach (var delay in delays)
        {
            req.NextWorkflow.StepId = request.DelayWithStepIds.First(d => d.DelayId == delay.Id).StepId;
            apptaskItems.Add(new AddApptaskItemRequest
            {
                BusinessId = delay.Id,
                TaskParams = req
            });
        }

        var taskId = await _apptaskDomainService.AddAsync(new AddApptaskRequest
        {
            TaskType = ETaskType.OrderDelay,
            Priority = 0,
            ApptaskItems = apptaskItems
        }, cancellation);

        if (!string.IsNullOrEmpty(taskId))
        {
            foreach (var orderDelay in delays)
            {
                orderDelay.DelayState = EDelayState.BatchProcessing;
            }
            await _orderDelayRepository.Updateable(delays)
                .UpdateColumns(d=>new {d.DelayState})
                .ExecuteCommandAsync(cancellation);
        }
    }

    private FakeSessionContext CreateFakeSessionContext(ISessionContext sessionContext)
    {
        return new FakeSessionContext
        {
            UserId = sessionContext.UserId,
            UserName = sessionContext.UserName,
            Phone = sessionContext.Phone,
            Roles = sessionContext.Roles,
            OrgId = sessionContext.OrgId,
            OrgName = sessionContext.OrgName,
            OrgLevel = sessionContext.OrgLevel,
            OrgAreaCode = sessionContext.OrgAreaCode,
            OrgIsCenter = sessionContext.OrgIsCenter,
            OrgAreaName = sessionContext.OrgAreaName,
            AreaId = sessionContext.AreaId,
            ClientId = sessionContext.ClientId,
            StaffNo = sessionContext.StaffNo,
            OpenId = sessionContext.OpenId
        };
    }
}