using Hotline.Api.Controllers;
using Hotline.Application.Snapshot;
using Hotline.Application.Snapshot.Contracts;
using Hotline.Caching.Interfaces;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.Identity.Accounts;
using Hotline.Identity.Roles;
using Hotline.Orders;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Repository.SqlSugar.Snapshot;
using Hotline.Settings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Snapshot;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.Snapshot;
using Hotline.Share.Requests;
using Hotline.Share.Tools;
using Hotline.Snapshot;
using Hotline.Snapshot.IRepository;
using Hotline.Tests.Mock;
using Hotline.ThirdAccountDomainServices;
using Hotline.ThirdAccountDomainServices.Interfaces;
using Hotline.Users;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using NPOI.SS.Formula.Functions;
using Senparc.Weixin.MP;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XF.Domain.Cache;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Tests.Application;
public class OrderSnapshotApplicationTest : TestBase
{
    private readonly OrderServiceMock _orderServiceMock;
    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
    private readonly IOrderSnapshotRepository _orderSnapshotRepository;
    private readonly IOrderSnapshotApplication _orderSnapshotApplication;
    private readonly ISnapshotApplication _snapshotApplication;
    private readonly IIndustryLogRepository _industryLogRepository;
    private readonly ICommunityInfoRepository _communityInfoRepository;
    private readonly IRedPackAuditRepository _redPackAuditRepository;
    private readonly IRedPackRecordRepository _redPackRecordRepository;
    private readonly ISnapshotLabelLogRepository _snapshotLabelLogRepository;
    private readonly IRedPackApplication _redPackApplication;
    private readonly IOrderRepository _orderRepository;
    private readonly IIndustryCaseRepository _industryCaseRepository;
    private readonly ISnapshotPointsRecordRepository _pointsRecordRepository;
    private readonly IIndustryRepository _industryRepository;
    private readonly OrderController _orderController;

    public OrderSnapshotApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderSnapshotRepository orderSnapshotRepository, IOrderSnapshotApplication orderSnapshotApplication, ISnapshotApplication snapshotApplication, IIndustryLogRepository industryLogRepository, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IRedPackRecordRepository redPackRecordRepository, ISnapshotLabelLogRepository snapshotLabelLogRepository, ITypedCache<SystemSetting> cacheSettingData, IRedPackApplication redPackApplication, IOrderRepository orderRepository, ThirdAccounSupplierFactory thirdAccountDomainFactory, IIndustryCaseRepository industryCaseRepository, ISnapshotPointsRecordRepository pointsRecordRepository, IIndustryRepository industryRepository, OrderController orderController, IServiceProvider serviceProvider) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory, serviceProvider)
    {
        _orderServiceMock = orderServiceMock;
        _systemDicDataCacheManager = systemDicDataCacheManager;
        _orderSnapshotRepository = orderSnapshotRepository;
        _orderSnapshotApplication = orderSnapshotApplication;
        _snapshotApplication = snapshotApplication;
        _industryLogRepository = industryLogRepository;
        _communityInfoRepository = communityInfoRepository;
        _redPackAuditRepository = redPackAuditRepository;
        _redPackRecordRepository = redPackRecordRepository;
        _snapshotLabelLogRepository = snapshotLabelLogRepository;
        _redPackApplication = redPackApplication;
        _orderRepository = orderRepository;
        _industryCaseRepository = industryCaseRepository;
        _pointsRecordRepository = pointsRecordRepository;
        _industryRepository = industryRepository;
        _orderController = orderController;
        _orderController.ControllerContext = new ControllerContext
        {
            HttpContext = new DefaultHttpContext()
        };
    }

    /// <summary>
    /// 测试办理步骤中没有附件信息异常
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task SnapshotOrder_Workflow_NextsStep_Document_Test()
    {
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin)
            .办理到派单员(SetZuoXi)
            .办理到一级部门(SetPaiDanYuan)
            .StepHandle(async order =>
            {
                Set一级部门();
                var steps = await _orderController.GetNextStepsWithRecommend(order.Id);
                steps.DocumentFiles.ShouldNotBeNull();
                steps.DocumentFiles.NotNullOrEmpty().ShouldBeTrue();
            })
            .GetCreateResult();
    }

    [Fact]
    public async Task SnapshotOrder_CompliantType_Test()
    {
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin)
            .办理到一级部门(SetZuoXi)
            .办理到归档(Set一级部门, data =>
            {
                data.CompliantType = ECompliantType.First;
                data.VerifyType = "现场";
                data.IsCheckList = true;
            });
    }

    [Theory]
    [InlineData(true)]
    [InlineData(false)]
    public async Task SnapshotOrder_AddPoints_Test(bool 是受理范围)
    {
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
            .StepHandle(async order =>
            {
                if (是受理范围 == false)
                {
                    var entity = _orderRepository.Get(order.Id);
                    entity.HotspotId = "181301";
                    await _orderRepository.UpdateAsync(entity);
                }
            })
            .办理到一级部门(SetZuoXi)
            .办理到归档(Set一级部门, data =>
            {
                data.CompliantType = ECompliantType.First;
                data.VerifyType = "现场";
                data.IsCheckList = true;
            }).GetCreateResult();
        var points = await _pointsRecordRepository.Queryable()
            .Where(m => m.OrderId == order.Id && m.Direction == EPointsDirection.In && m.Source == EPointsSource.Report)
            .FirstAsync();
        if (是受理范围)
            points.ShouldNotBeNull();
        else
            points.ShouldBeNull();
    }

    /// <summary>
    /// 随手拍网格员超时:
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task SnapshotWorkflow_WorkflowModuleError_est()
    {
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin)
            .办理到一级部门(SetZuoXi)
            .StepHandle(async order =>
            {
                var detail = await _orderController.Get(order.Id);
                detail.Workflow.ModuleCode.ShouldBe(WorkflowModuleConsts.OrderHandleSnapshot);
            }
            ).GetCreateResult();
    }

    /// <summary>
    /// 随手拍网格员超时:
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task SnapshotWorkflow_Guider_Timeout_Test()
    {
        SetSettingCache(SettingConstants.OvertimeBack, "0.00027778");
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
            .办理到网格员(SetZuoXi)
            .StepHandle(async order =>
            {
                Thread.Sleep(5 * 1000);
                var orderEntity = await _orderRepository.GetAsync(order.Id);
                orderEntity.ActualHandleStepName.ShouldBe("工单标记");
            }
            ).GetCreateResult();
    }

    /// <summary>
    /// 随手拍办理流程:
    ///     坐席
    ///     网格员
    ///     派单员
    ///     一级部门
    ///     归档
    ///     发布工单
    ///     政法委部门审核网格红包
    ///     应急局部门审核网格员红包
    ///     部门审核市民红包
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task SnapshotWorkflow_Guider_Test()
    {
        SetSettingCache(SettingConstants.OvertimeBack, "4");
        var snapshotLabels = _systemDicDataCacheManager.SnapshotOrderLabel;
        var inputLable = snapshotLabels.Where(m => m.DicDataValue == "bss").ToList();
        var industryCase = await _industryCaseRepository.Queryable().Where(m => m.IsEnable == true).FirstAsync();
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
            .办理到网格员(SetZuoXi)
            .StepHandle(async (order, mock) =>
            {
                var industry = await _industryRepository.Queryable()
                .LeftJoin<OrderSnapshot>((industry, snapshot) => industry.Id == snapshot.IndustryId)
                .Where((industry, snapshot) => snapshot.Id == order.Id)
                .Select((industry, snapshot) => new Industry(), true)
                .FirstAsync();
                var pointsRecord = await _pointsRecordRepository.Queryable().Where(m => m.OrderId == order.Id && m.Source == EPointsSource.Report).FirstAsync();
                pointsRecord.ShouldNotBeNull();
                pointsRecord.Points.ShouldBe(industry.ReportPoints!.Value);

                await _snapshotApplication.PostOrderGuiderSystemAsync(order.Id, CancellationToken.None);
                var orderSnapshot = await _orderSnapshotRepository.GetAsync(order.Id);
                orderSnapshot.IndustryName = "修改行业名称";
                await _orderSnapshotRepository.UpdateAsync(orderSnapshot);
                var industryLog = await _industryLogRepository.Queryable()
                    .Where(m => m.OrderId == order.Id)
                    .FirstAsync();
                industryLog.ShouldNotBeNull();
                industryLog.IndustryName.ShouldBe("修改行业名称");
                await _orderSnapshotRepository.Updateable()
                    .SetColumns(m => m.IndustryName, industryLog.OldIndustryName)
                    .Where(m => m.Id == order.Id)
                    .ExecuteCommandAsync();
                await _orderRepository.Updateable()
                    .SetColumns(m => m.OrderTagCode, "DHZY")
                    .Where(m => m.Id == order.Id)
                    .ExecuteCommandAsync();
                orderSnapshot = await _orderSnapshotRepository.GetAsync(order.Id);
                var replyDto = mock.GetGuiderSystemInDto(orderSnapshot.NetworkENumber);
                await _snapshotApplication.SaveGuiderSystemReplyAsync(replyDto, CancellationToken.None);
                orderSnapshot = await _orderSnapshotRepository.GetAsync(order.Id);
                orderSnapshot.CommunityName.ShouldNotBeNull();
                var orderReply = await _orderSnapshotRepository.GetByNetworkENumberAsync(replyDto.AppealNumber);
                orderReply.IsDanger.ShouldBe(replyDto.IsHiddenDanger == "1" ? true : false);
                orderReply.MemberMobile.ShouldBe(replyDto.MemberMobile);
                orderReply.MemberName.ShouldBe(replyDto.MemberName);
                orderReply.NetworkRemark.ShouldBe(replyDto.ReplyContent);
                orderReply.ReplyDate.Value.ToString("yyyy-MM-dd hh:mm:ss").ShouldBe(replyDto.ReplyDate);
                var community = await _communityInfoRepository.GetAsync(replyDto.OrgId);
                community.ShouldNotBeNull();
                community.Name.ShouldBe(replyDto.OrgName);
                community.FullName.ShouldBe(replyDto.OrgFullName);
                var orderEntity = await _orderRepository.GetAsync(order.Id);
                orderEntity.ActualHandleStepName.ShouldBe("工单标记");
            })
            .办理到派单员(Set班长)
            .办理到一级部门(SetPaiDanYuan)
            .办理到归档(Set一级部门, data =>
            {
                data.IsDangerDepartment = true;
                data.IndustryCase = industryCase.Id;
                data.IsRectifyDepartment = true;
                data.CompliantType = ECompliantType.First;
            })
            .StepHandle(async order =>
            {
                var snapshot = await _orderSnapshotRepository.GetAsync(order.Id);
                snapshot.IndustryCase.ShouldBe(industryCase.Id);
                var orderDetail = await _orderController.Get(order.Id);
                orderDetail.IndustryName.Contains(" ").ShouldBeTrue();
            })
            .发布工单(SetZuoXi, inputLable.Select(m => new Kv(m.DicDataName, m.DicDataName)).ToList())
            .StepHandle(async order =>
            {
                var log = _snapshotLabelLogRepository.Queryable().Where(m => m.OrderId == order.Id).First();
                log.ShouldNotBeNull();
                await _orderSnapshotApplication.UpdateIsEmphasisAsync(new UpdateIsEmphasisInDto { Ids = [order.Id] });
                var snapshot = _orderSnapshotRepository.Get(order.Id);
                snapshot.LabelName.ShouldBe(string.Join(',', inputLable.Select(m => m.DicDataName)), "label异常");
                snapshot.IsEmphasis.ShouldBe(true);
            })
            .部门审核网格员红包(Set政法委)
            .部门审核网格员红包(Set应急管理局)
            .StepHandle(async order =>
            {
                var redPackRecord = _redPackRecordRepository.Queryable()
                .Where(m => m.OrderId == order.Id && m.PeopleType == EReadPackUserType.Guider)
                .First();
                redPackRecord.Amount.ShouldNotBe(0);
            })
            .部门审核市民红包(Set应急管理局)
            .StepHandle(async order =>
            {
                var redPackAudit = _redPackAuditRepository.Queryable().Where(m => m.OrderId == order.Id).First();
                redPackAudit.Status.ShouldBe(ERedPackAuditStatus.Agree);
                var redPackRecord = _redPackRecordRepository.Queryable().Where(m => m.OrderId == order.Id).First();
                redPackRecord.ShouldNotBeNull();
            })
            .部门审核特殊红包(Set应急管理局)
            .StepHandle(async order =>
            {
                var baseData = await _redPackApplication.GetRedPackRecordBaseDataAsync(order.Id);
                baseData.AuditType.ShouldNotBeNull();
                baseData.AuditTypeCode.ShouldNotBeNull();
                baseData.Amount.ShouldNotBeNull();

                var specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10, No = order.No, Status = 1 }).ToListAsync();
                var specialRedAudit = specialRedAuditItems.FirstOrDefault();
                specialRedAudit.ShouldNotBeNull();
                var a = _systemDicDataCacheManager.SnapshotReplenishType.First();
                var b = _systemDicDataCacheManager.SnapshotRedPackSpecialType.First();
                var inDto = new UpdateRedPackRecordInDto
                {
                    RedPackAuditId = baseData.RedPackAuditId,
                    Name = "收银人",
                    BankCardNo = "1233921321",
                    OpenBank = "建设银行",
                    ReplenishAmount = 10,
                    ReplenishTime = DateTime.Now,
                    ReplenishRemark = "补充发放备注",
                    IsSendSMS = false,
                    ReplenishType = a.DicDataName,
                    ReplenishTypeId = a.DicDataValue,
                    AuditType = b.DicDataName,
                };

                await _redPackApplication.UpdateRedPackSpecialRecordAsync(inDto); // 补充发放
                specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10, Status = 1, No = order.No }).ToListAsync();
                specialRedAudit = specialRedAuditItems.First();
                specialRedAudit.ShouldNotBeNull();
                specialRedAudit.BankCardNo.ShouldBe(inDto.BankCardNo);
                specialRedAudit.OpenBank.ShouldBe(inDto.OpenBank);

                try
                {
                    await _redPackApplication.RevocationRedPackSpecialAuditAsync([specialRedAudit.Id]);
                }
                catch (UserFriendlyException e)
                {
                    e.Message.ShouldBe("该工单已发放红包，不能撤销审批");
                }

                var redPack = await _redPackApplication.GetRedPackAuditItems(new SnapshotOrderAuditItemsInDto() { No = order.No }).FirstAsync();

                await _redPackApplication.UpdateRedPackAuditRemarkAsync(new UpdateRedPackAuditRemarkInDto()
                {
                    RedPackAuditId = redPack.Id,
                    AcutalAmount = 0,
                    SendRemarks = "单元测试备注",
                    IsSend = true
                }); // 添加备注

                SetWeiXin();
                var redPackItems = await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Unreceived }, CancellationToken.None);
                var redPackRecord = redPackItems.Where(m => m.OrderId == order.Id).FirstOrDefault();
                redPackRecord.ShouldNotBeNull();
                redPackRecord.Amount.ShouldBe(0);

                Set应急管理局();
                await _redPackApplication.UpdateRedPackAuditRemarkAsync(new UpdateRedPackAuditRemarkInDto()
                {
                    RedPackAuditId = redPackRecord.RedPackAuditId,
                    AcutalAmount = 11,
                    SendRemarks = "单元测试备注",
                    IsSend = true
                }); // 添加备注

                SetWeiXin();
                redPackItems = await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Received }, CancellationToken.None);
                redPackRecord = redPackItems.Where(m => m.OrderId == order.Id).FirstOrDefault();
                redPackRecord.ShouldNotBeNull();
                redPackRecord.Amount.ShouldBe(11);
            })
            .GetCreateResult();
        order.Id.ShouldNotBeNull();
    }

    /// <summary>
    /// 随手拍办理流程
    /// 工单标注 : 验证数据是否保存正确
    /// 获取已标注集合: 验证是否有已标注的数据
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task SnapshotWrokflow_Test()
    {
        var snapshotLabels = _systemDicDataCacheManager.SnapshotOrderLabel;
        var inputLable = snapshotLabels.Where(m => m.DicDataValue == "bss").ToList();
        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
            .办理到工单标注(SetZuoXi)
            .办理到派单员(Set班长, false)
            .办理到归档(SetPaiDanYuan)
            .发布工单(SetPaiDanYuan, inputLable.Select(m => new Kv { Key = m.DicDataValue, Value = m.DicDataName }).ToList())
            .GetCreateResult();
        order.Id.ShouldNotBeNull();

        var snapshot = await _orderSnapshotRepository.GetAsync(order.Id);
        // 验证工单标注是否生效
        snapshot.ShouldNotBeNull();
        snapshot.IsTruthDepartment.ShouldBe(false);
        snapshot.LabelName.ShouldBe(string.Join('|', inputLable.Select(m => m.DicDataName)));
        snapshot.Labels.ShouldNotBeNull();
        snapshot.Labels.Count.ShouldBe(inputLable.Count);

        snapshot.IsSafetyDepartment.ShouldBe(false);

        var labelLog = await _orderSnapshotApplication.GetLabelOrderSnapshotLogItems(new LabelOrderSnapshotLogItemsInDto()).ToPagedListAsync(new PagedRequest());
        labelLog.Items.Any(m => m.Title.IsNullOrEmpty()).ShouldBe(false);
        labelLog.Items.Any(m => m.SourceChannel.IsNullOrEmpty()).ShouldBe(false);

        var sigedItems = await _orderSnapshotApplication.GetLabeledOrderSnapshotItems(new LabeledOrderSnapshotItemsInDto()).ToListAsync();
        sigedItems.Any(m => m.OrderId == order.Id).ShouldBe(true);
    }

    [Fact]
    public async Task GetOrderSnapshotElectrogasItems_Test()
    {
        var inDto = new OrderSnapshotItemsInDto();
        var items = (await _orderSnapshotApplication.GetOrderSnapshotElectrogasItems(inDto).ToPagedListAsync(inDto));
        items.Total.ShouldNotBe(0);
    }
}

