using DotNetCore.CAP;
using Hotline.EventBus;
using Hotline.Orders;
using Hotline.Push.Notifies;
using Hotline.Share.Dtos.Push;
using Hotline.Share.Enums.Push;
using Hotline.Share.Tools;
using Mapster;
using MapsterMapper;
using Microsoft.Extensions.Logging;
using System.Text.RegularExpressions;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Push.FWMessage;

/// <summary>
/// 
/// </summary>
public class PushDomainService : IPushDomainService, IScopeDependency
{
    #region 注入
    private readonly IRepository<Message> _messageRepository;
    private readonly IMapper _mapper;
    private readonly IRepository<MessageTemplate> _messageTemplateRepository;
    private readonly ICapPublisher _capPublisher;
    private readonly ILogger<PushDomainService> _logger;
    private readonly IOrderVisitRepository _orderVisitRepository;
    private readonly Publisher _publisher;


    /// <summary>
    /// 
    /// </summary>
    /// <param name="messageRepository"></param>
    /// <param name="mapper"></param>
    /// <param name="messageTemplateRepository"></param>
    /// <param name="capPublisher"></param>
    /// <param name="logger"></param>
    public PushDomainService(IRepository<Message> messageRepository,
        IMapper mapper,
        IRepository<MessageTemplate> messageTemplateRepository,
        ICapPublisher capPublisher,
        ILogger<PushDomainService> logger
,
        IOrderVisitRepository orderVisitRepository,
        Publisher publisher)
    {
        _messageRepository = messageRepository;
        _mapper = mapper;
        _messageTemplateRepository = messageTemplateRepository;
        _capPublisher = capPublisher;
        _logger = logger;
        _orderVisitRepository = orderVisitRepository;
        _publisher = publisher;
    }
    #endregion

    /// <summary>
    /// 短信发送
    /// </summary>
    /// <param name="messageDto"></param>
    /// <param name="cancellation"></param>
    /// <returns></returns>
    public async Task PushMsgAsync(MessageDto messageDto, CancellationToken cancellation)
    {
        if (messageDto == null)
            throw UserFriendlyException.SameMessage("消息不能为空！");

        if (string.IsNullOrEmpty(messageDto.TemplateCode) && string.IsNullOrEmpty(messageDto.Content))
            throw UserFriendlyException.SameMessage("模板和内容不能同时为空！");

        #region 替换模板内容
        //如果模板为空，参数为空则直接用短信内容
        if (!string.IsNullOrEmpty(messageDto.TemplateCode))
        {
            //查询模板信息
            var messageTemplate = await _messageTemplateRepository.GetAsync(p => p.Code == messageDto.TemplateCode, cancellation);
            if (messageTemplate == null || string.IsNullOrEmpty(messageTemplate.Content))
                throw UserFriendlyException.SameMessage("未找到模板短信！");

            string Template = messageTemplate.Content;
            if (messageDto.Params != null && messageDto.Params.Count > 0)
            {
                //正则查询模板中需要替换的内容
                Regex regex = new(@"\{[a-zA-Z0-9]{1,}\}");
                var matches = regex.Matches(Template);
                if (matches != null && matches.Count != messageDto.Params.Count)
                    //参数与需要替换的字符数不匹配
                    throw UserFriendlyException.SameMessage("模板需要参数与实际传递参数个数不匹配！");
                //reason = "模板需要参数与实际传递参数个数不匹配！";

                //根据正则查询出来的匹配项替换内容
                for (int i = 0; i < matches.Count; i++)
                    Template = Template.Replace(matches[i].ToString(), messageDto.Params[i]);

            }
            messageDto.Content = Template;

        }
        #endregion
        var message = _mapper.Map<Message>(messageDto);
        //验证手机号是否正确
        var isRight = message.TelNumber.IsPhoneNumber();
        //如果不正确直接写入失败，不往短信平台推送
        if (isRight == false)
        {
            message.Status = EPushStatus.Failed;
            message.SendState = ESendState.Failed;
            message.Reason = "手机号码格式错误";
        }

        var id = await _messageRepository.AddAsync(message, cancellation);//写入本地数据库

        //手机号码正确推送短信
        if (isRight)
        {
            PushMessageDto pushMessage = new()
            {
                ClientId = "Hotline",
                ExternalId = id,
                Content = message.Content,
                Remark = message.Remark,
                Name = message.Name,
                TelNumber = message.TelNumber
            };
            //消息队列
            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.SendSms, pushMessage, cancellationToken: cancellation);
        }
    }

    /// <summary>
    /// 修改短信推送状态
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellation"></param>
    /// <returns></returns>
    public async Task PushMsgUpdateStateAsync(PushReceiveMessageDto dto, CancellationToken cancellation)
    {
        if (dto.Type != "2")
        {
            var data = await _messageRepository.GetAsync(p => p.Id == dto.ExternalId, cancellation);
            if (data != null)
            {
                if (dto.Type == "0")
                {
                    if (dto.SendState == ESendState.Sending)
                    {
                        data.SmsWaitSendingId = dto.SmsWaitSendingId;
                        data.SendState = ESendState.Sending;
                        data.Status = EPushStatus.Success;
                    }
                    else
                        data.Status = EPushStatus.Failed;

                    await _messageRepository.UpdateAsync(data, cancellation);
                }
                else if (dto.Type == "1")
                {
                    data.SendTime = Convert.ToDateTime(dto.SendTime);
                    data.SendState = dto.SendState;
                    data.MsgCount = dto.MsgCount;
                    data.SmsSendingCompletedId = dto.SmsSendingCompletedId;
                    await _messageRepository.UpdateAsync(data, cancellation);
                }
            }
        }
        else if (dto.Type == "2")
        {
            var messData = await _messageRepository.Queryable()
                .Where(p => p.TelNumber == dto.TelNumber && (p.PushBusiness == EPushBusiness.VisitSms || p.PushBusiness == EPushBusiness.SearchSms)
                && p.IsSmsReply == false)
                .OrderBy(p => p.CreationTime)
                .FirstAsync();
            if (messData != null)
            {
                messData.IsSmsReply = true;
                messData.SmsReplyTime = Convert.ToDateTime(dto.SmsReplyTime);
                messData.SmsReplyContent = dto.SmsReplyContent;
                await _messageRepository.UpdateAsync(messData, cancellation);

                var notify = messData.Adapt<ReceiveMessageNotify>();
                notify.NotifyDto.Type = dto.Type;
                await _publisher.PublishAsync(notify, PublishStrategy.ParallelWhenAll, cancellation);
            }
        }

    }

    /// <summary>
    /// 修改短信推送状态
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellation"></param>
    /// <returns></returns>
    public async Task PushMsgUpdateStateNewAsync(PushReceiveMessageDto dto, CancellationToken cancellation)
    {
        var data = await _messageRepository.GetAsync(p => p.Id == dto.ExternalId, cancellation);
        if (data != null)
        {
            data.SmsWaitSendingId = dto.SmsWaitSendingId;
            data.Status = EPushStatus.Success;
            data.SendTime = Convert.ToDateTime(dto.SendTime);
            data.SendState = dto.SendState;
            data.MsgCount = dto.MsgCount;
            data.SmsSendingCompletedId = dto.SmsSendingCompletedId;
            data.IsSmsReply = dto.IsSmsReply;
            data.SmsReplyTime = Convert.ToDateTime(dto.SmsReplyTime);
            data.SmsReplyContent = dto.SmsReplyContent;
            data.Reason = dto.Reason;
            await _messageRepository.UpdateAsync(data, cancellation);
        }
    }

}
