using QYZH.InteractiveMagazine.Common.Helpers;
using QYZH.InteractiveMagazine.Infrastructure.OSS;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using SqlSugar;
using System.Text;
using System.Text.Json;

namespace QYZH.InteractiveMagazine.WorkService.Consumers;

/// <summary>
/// 期刊二维码生成消费者
/// </summary>
public class UserJournalQrCodeGenerateConsumer(
    ILogger<UserJournalQrCodeGenerateConsumer> logger,
    IServiceScopeFactory scopeFactory,
    OssService ossService) : IQueueConsumer
{
    public string Exchange => "ex.journal";

    public string QueueName => "mq.journal.qrcode.generate";

    public string RoutingKey => "rk.journal.qrcode.generate";

    public async Task HandleAsync(byte[] message, CancellationToken cancellationToken = default)
    {
        var content = Encoding.UTF8.GetString(message);
        logger.LogInformation("收到期刊二维码生成消息: {Message}", content);

        var data = JsonSerializer.Deserialize<GenerateUserJournalQrCodeMessage>(content, new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        }) ?? throw new InvalidOperationException("期刊二维码生成消息为空");

        if (data.RecordIds.Count == 0)
        {
            logger.LogWarning("期刊二维码生成消息缺少记录Id");
            return;
        }

        using var scope = scopeFactory.CreateScope();
        var client = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
        var operatorName = string.IsNullOrWhiteSpace(data.OperatorName) ? "System" : data.OperatorName;

        foreach (var recordId in data.RecordIds.Distinct())
        {
            await GenerateQrCodeImageAsync(client, recordId, operatorName, cancellationToken);
        }
    }

    public async Task OnErrorAsync(byte[] message, Exception exception)
    {
        logger.LogError(exception, "处理期刊二维码生成消息失败: {Message}", Encoding.UTF8.GetString(message));

        try
        {
            var data = JsonSerializer.Deserialize<GenerateUserJournalQrCodeMessage>(Encoding.UTF8.GetString(message), new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });

            if (data?.RecordIds.Count > 0)
            {
                using var scope = scopeFactory.CreateScope();
                var client = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
                var operatorName = string.IsNullOrWhiteSpace(data.OperatorName) ? "System" : data.OperatorName;
                await client.Updateable<UserJournal>()
                    .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Failed)
                    .SetColumns(uj => uj.UpdatedBy == operatorName)
                    .SetColumns(uj => uj.UpdatedAt == DateTime.Now)
                    .Where(uj => data.RecordIds.Contains(uj.Id) && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating)
                    .ExecuteCommandAsync();
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "标记期刊二维码生成失败状态异常");
        }
    }

    private async Task GenerateQrCodeImageAsync(ISqlSugarClient client, long recordId, string operatorName, CancellationToken cancellationToken)
    {
        try
        {
            var record = await client.Queryable<UserJournal>()
                .Where(uj => uj.Id == recordId && !uj.IsDeleted)
                .FirstAsync(cancellationToken);

            if (record == null || record.Status != (int)UserJournalStatusEnum.Generating)
            {
                return;
            }

            var qrCodeContent = BuildQrCodeContent(record.JournalId, record.Id);
            var qrCodeKey = $"journal/qrcode/{record.JournalId}/{record.Id}.png";
            using var qrCodeStream = new MemoryStream(QrCodeHelper.GeneratePng(qrCodeContent));
            var uploadedKey = ossService.PutObject(qrCodeKey, qrCodeStream);
            if (string.IsNullOrWhiteSpace(uploadedKey))
            {
                throw new BusinessException("二维码图片上传失败", ResultCode.GLOBAL_ERROR);
            }

            await client.Updateable<UserJournal>()
                .SetColumns(uj => uj.QrCodeUrl == uploadedKey)
                .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Active)
                .SetColumns(uj => uj.UpdatedBy == operatorName)
                .SetColumns(uj => uj.UpdatedAt == DateTime.Now)
                .Where(uj => uj.Id == recordId && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating)
                .ExecuteCommandAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "生成期刊二维码失败，RecordId: {RecordId}", recordId);
            await client.Updateable<UserJournal>()
                .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Failed)
                .SetColumns(uj => uj.UpdatedBy == operatorName)
                .SetColumns(uj => uj.UpdatedAt == DateTime.Now)
                .Where(uj => uj.Id == recordId && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating)
                .ExecuteCommandAsync(cancellationToken);
        }
    }

    private static string BuildQrCodeContent(long journalId, long id)
    {
        return JsonSerializer.Serialize(new { JournalId = journalId, Id = id });
    }
}
