using Application.Abstractions.Data;
using Application.Abstractions.YouTube;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Infrastructure.YouTube;

/// <summary>
/// 1시간마다 활성 채널의 YouTube 정보를 갱신하여 Redis 캐시에 저장
/// channels.list는 id 파라미터로 최대 50개 채널을 한 번에 조회 가능 (1 unit/요청)
/// 채널 50개 이하 → 1시간에 1 unit만 사용
/// </summary>
internal sealed class YouTubeChannelCacheRefreshService(
    IServiceScopeFactory scopeFactory,
    IYouTubeApiService youTubeApi,
    IYouTubeChannelCache channelCache,
    ILogger<YouTubeChannelCacheRefreshService> logger
) : BackgroundService
{
    private static readonly TimeSpan RefreshInterval = TimeSpan.FromHours(1);
    private static readonly TimeSpan InitialDelay = TimeSpan.FromSeconds(15);
    private const int BatchSize = 50; // YouTube API 최대 50개/요청

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await Task.Delay(InitialDelay, stoppingToken);
        logger.LogInformation("[ChannelCache] 채널 캐시 갱신 서비스 시작 — 주기: {Interval}시간", RefreshInterval.TotalHours);

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await RefreshAllChannelsAsync(stoppingToken);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "[ChannelCache] 채널 캐시 갱신 중 오류");
            }

            await Task.Delay(RefreshInterval, stoppingToken);
        }
    }

    private async Task RefreshAllChannelsAsync(CancellationToken ct)
    {
        // DB에서 활성 채널 SID 목록 조회 (Scoped DbContext)
        List<string> channelIds;
        using (var scope = scopeFactory.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<IAppDbContext>();
            channelIds = await db.Channel.AsNoTracking().Where(c => c.IsActive).Select(c => c.SID).ToListAsync(ct);
        }

        if (channelIds.Count == 0)
        {
            return;
        }

        // 50개씩 배치로 YouTube API 호출
        var refreshed = 0;
        for (var i = 0; i < channelIds.Count; i += BatchSize)
        {
            var batch = channelIds.Skip(i).Take(BatchSize).ToList();
            var results = await youTubeApi.GetChannelsByIdsAsync(batch, ct);

            foreach (var info in results)
            {
                await channelCache.SetAsync(info);
                refreshed++;
            }

            // 배치 간 1초 대기 (API rate limit 방어)
            if (i + BatchSize < channelIds.Count)
            {
                await Task.Delay(TimeSpan.FromSeconds(1), ct);
            }
        }

        logger.LogInformation("[ChannelCache] {Refreshed}/{Total} 채널 캐시 갱신 완료", refreshed, channelIds.Count);
    }
}