using Microsoft.EntityFrameworkCore;
using bitforum.Constants;
using bitforum.Services;

namespace bitforum.Workers
{
    public class MailQueueWorker : BackgroundService
    {
        private readonly ILogger<MailQueueWorker> _logger;
        private readonly IServiceScopeFactory _scopeFactory;
        private readonly int _workerCount = 2; // 병렬 처리할 Worker 개수

        public MailQueueWorker(ILogger<MailQueueWorker> logger, IServiceScopeFactory scopeFactory)
        {
            _logger = logger;
            _scopeFactory = scopeFactory;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("MailQueueWorker 시작됨.");

            // 병렬 작업자 처리 지시
            await Task.WhenAll(
                Enumerable.Range(0, _workerCount).Select(_ => Task.Run(() => ProcessQueueAsync(stoppingToken))).ToArray()
            );
        }

        private async Task ProcessQueueAsync(CancellationToken stoppingToken)
        {
            var mailService = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<IMailService>();

            while (!stoppingToken.IsCancellationRequested)
            {
                using (var scope = _scopeFactory.CreateScope())
                {
                    var db = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();

                    // 발송되지 않는 메일 확인
                    var email = await db.EmailLog.Where(x => x.Status == MailStatus.Pending || x.Status == MailStatus.Processing).OrderBy(x => x.CreatedAt).Take(1).FirstOrDefaultAsync(stoppingToken);

                    if (email is null)
                    {
                        await Task.Delay(3000, stoppingToken);
                        continue;
                    }

                    try
                    {
                        // 상태를 "Processing"으로 변경하여 중복 처리 방지
                        email.Status = MailStatus.Processing;
                        await db.SaveChangesAsync(stoppingToken);

                        // 메일 전송 시도
                        await mailService.SendEmailAsync(new SendData(
                            email.ToAddress, email.Subject, email.Message ?? string.Empty
                        ));

                        // 성공 시 "Sent"로 변경
                        email.Status = MailStatus.Sent;
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, "메일 전송 중 오류 발생");
                        email.Status = MailStatus.Failed;
                        continue;
                    }

                    email.ProcessedAt = DateTime.UtcNow;

                    await db.SaveChangesAsync(stoppingToken);
                }
            }
        }

        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation($"{nameof(MailQueueWorker)} is stopping.");

            await base.StopAsync(stoppingToken);
        }
    }
}
