using Microsoft.Extensions.Logging;
using MktXService.Domain.AggregatesModel.CampaignAggregate;
using MktXService.Domain.AggregatesModel.ContactAggregate;
using MktXService.Domain.AggregatesModel.TemplateAggregate;
using MktXService.Infrastructure.ExternalServices.Twitter;
using Quartz;

namespace MktXService.Infrastructure.BackgroundJobs;

/// <summary>
/// EN: Background job for processing message queue and sending to Twitter.
/// VI: Background job để xử lý hàng đợi tin nhắn và gửi đến Twitter.
/// </summary>
/// <remarks>
/// EN: Handles rate limiting and batch processing for campaign messages.
/// VI: Xử lý rate limiting và xử lý hàng loạt cho tin nhắn chiến dịch.
/// </remarks>
[DisallowConcurrentExecution]
public class MessageProcessorJob : IJob
{
    private readonly ITwitterApiClient _twitterClient;
    private readonly ITemplateRepository _templateRepository;
    private readonly ICampaignRepository _campaignRepository;
    private readonly IContactRepository _contactRepository;
    private readonly ILogger<MessageProcessorJob> _logger;

    // EN: Twitter DM rate limit: 500 per 24 hours per user
    // VI: Giới hạn DM Twitter: 500 mỗi 24 giờ cho mỗi người dùng
    private const int MaxMessagesPerBatch = 50;
    private const int DelayBetweenMessagesMs = 1000;

    public MessageProcessorJob(
        ITwitterApiClient twitterClient,
        ITemplateRepository templateRepository,
        ICampaignRepository campaignRepository,
        IContactRepository contactRepository,
        ILogger<MessageProcessorJob> logger)
    {
        _twitterClient = twitterClient;
        _templateRepository = templateRepository;
        _campaignRepository = campaignRepository;
        _contactRepository = contactRepository;
        _logger = logger;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        _logger.LogInformation("MessageProcessorJob started at {Time}", DateTimeOffset.UtcNow);

        try
        {
            // EN: Get all running campaigns
            // VI: Lấy tất cả chiến dịch đang chạy
            var runningCampaigns = await GetRunningCampaignsAsync();

            foreach (var campaign in runningCampaigns)
            {
                if (context.CancellationToken.IsCancellationRequested)
                    break;

                await ProcessCampaignMessagesAsync(campaign, context.CancellationToken);
            }

            _logger.LogInformation("MessageProcessorJob completed");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "MessageProcessorJob failed");
            throw new JobExecutionException(ex, refireImmediately: false);
        }
    }

    private async Task<IEnumerable<Campaign>> GetRunningCampaignsAsync()
    {
        // EN: In production, this would query campaigns with status = Running
        // VI: Trong production, sẽ truy vấn các chiến dịch có status = Running
        // For now, return empty - the actual implementation depends on campaign state tracking
        return await Task.FromResult(Enumerable.Empty<Campaign>());
    }

    private async Task ProcessCampaignMessagesAsync(Campaign campaign, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Processing messages for campaign {CampaignId}", campaign.Id);

        if (!campaign.TemplateId.HasValue)
        {
            _logger.LogWarning("Campaign {CampaignId} has no template", campaign.Id);
            return;
        }

        // EN: Get the template
        // VI: Lấy template
        var template = await _templateRepository.GetByIdAsync(campaign.TemplateId.Value);
        if (template == null)
        {
            _logger.LogWarning("Template {TemplateId} not found for campaign {CampaignId}", 
                campaign.TemplateId, campaign.Id);
            return;
        }

        // EN: Get pending contacts from campaign queue (in production, from message queue)
        // VI: Lấy các liên hệ đang chờ từ hàng đợi chiến dịch (trong production, từ message queue)
        var pendingContacts = await GetPendingContactsAsync(campaign, MaxMessagesPerBatch);

        var sentCount = 0;
        var failedCount = 0;

        foreach (var contact in pendingContacts)
        {
            if (cancellationToken.IsCancellationRequested)
                break;

            try
            {
                // EN: Render the template with contact data
                // VI: Render template với dữ liệu liên hệ
                var variables = new Dictionary<string, object>
                {
                    ["username"] = contact.Username,
                    ["displayName"] = contact.DisplayName ?? contact.Username,
                    ["firstName"] = ExtractFirstName(contact.DisplayName)
                };

                var messageContent = template.Render(variables);

                // EN: Send the message
                // VI: Gửi tin nhắn
                var result = await _twitterClient.SendDirectMessageAsync(
                    contact.TwitterUserId,
                    messageContent,
                    cancellationToken);

                if (result.Success)
                {
                    sentCount++;
                    _logger.LogDebug("Sent message to {Username}", contact.Username);
                }
                else
                {
                    failedCount++;
                    _logger.LogWarning("Failed to send message to {Username}: {Error}", 
                        contact.Username, result.Error);
                }

                // EN: Respect rate limiting
                // VI: Tuân thủ rate limiting
                await Task.Delay(DelayBetweenMessagesMs, cancellationToken);
            }
            catch (Exception ex)
            {
                failedCount++;
                _logger.LogError(ex, "Error sending message to contact {ContactId}", contact.Id);
            }
        }

        // EN: Update campaign metrics
        // VI: Cập nhật metrics chiến dịch
        var currentMetrics = campaign.Metrics;
        var newMetrics = new CampaignMetrics(
            currentMetrics.TotalSent + sentCount,
            currentMetrics.Delivered + sentCount,
            currentMetrics.Opened,
            currentMetrics.Clicked,
            currentMetrics.Replied,
            currentMetrics.Failed + failedCount);

        campaign.UpdateMetrics(newMetrics);
        await _campaignRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Campaign {CampaignId}: Sent {Sent}, Failed {Failed}", 
            campaign.Id, sentCount, failedCount);
    }

    private async Task<IEnumerable<Contact>> GetPendingContactsAsync(Campaign campaign, int limit)
    {
        // EN: In production, this would query from a message queue or campaign state table
        // VI: Trong production, sẽ truy vấn từ message queue hoặc bảng trạng thái chiến dịch
        return await Task.FromResult(Enumerable.Empty<Contact>());
    }

    private static string ExtractFirstName(string? displayName)
    {
        if (string.IsNullOrWhiteSpace(displayName))
            return "";

        var parts = displayName.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        return parts.Length > 0 ? parts[0] : "";
    }
}

/// <summary>
/// EN: Schedule configuration for MessageProcessorJob.
/// VI: Cấu hình lịch trình cho MessageProcessorJob.
/// </summary>
public static class MessageProcessorJobSetup
{
    public static void ConfigureJob(IServiceCollectionQuartzConfigurator configurator)
    {
        var jobKey = new JobKey(nameof(MessageProcessorJob));

        configurator.AddJob<MessageProcessorJob>(opts => opts.WithIdentity(jobKey));

        configurator.AddTrigger(opts => opts
            .ForJob(jobKey)
            .WithIdentity($"{nameof(MessageProcessorJob)}-trigger")
            .WithSimpleSchedule(x => x
                .WithIntervalInSeconds(30)
                .RepeatForever()));
    }
}
