using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.SRFPlay.Api;
using Jellyfin.Plugin.SRFPlay.Services.Interfaces;
using Jellyfin.Plugin.SRFPlay.Utilities;
using Microsoft.Extensions.Logging;

namespace Jellyfin.Plugin.SRFPlay.Services;

/// <summary>
/// Service for refreshing content from SRF API.
/// </summary>
public class ContentRefreshService : IContentRefreshService
{
    private readonly ILogger<ContentRefreshService> _logger;
    private readonly ISRFApiClientFactory _apiClientFactory;

    /// <summary>
    /// Initializes a new instance of the <see cref="ContentRefreshService"/> class.
    /// </summary>
    /// <param name="loggerFactory">The logger factory.</param>
    /// <param name="apiClientFactory">The API client factory.</param>
    public ContentRefreshService(
        ILoggerFactory loggerFactory,
        ISRFApiClientFactory apiClientFactory)
    {
        _logger = loggerFactory.CreateLogger<ContentRefreshService>();
        _apiClientFactory = apiClientFactory;
    }

    /// <summary>
    /// Refreshes latest content from SRF API using Play v3.
    /// </summary>
    /// <param name="businessUnit">The business unit to fetch content for (e.g. "srf", "rts").</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>List of URNs for new content.</returns>
    public async Task<List<string>> RefreshLatestContentAsync(string businessUnit, CancellationToken cancellationToken)
    {
        var config = Plugin.Instance?.Configuration;
        if (config == null || !config.EnableLatestContent)
        {
            _logger.LogDebug("Latest content refresh is disabled");
            return new List<string>();
        }

        return await FetchVideosFromShowsAsync(
            businessUnit,
            minEpisodeCount: 0,
            maxShows: 20,
            videosPerShow: 1,
            contentType: "latest",
            cancellationToken).ConfigureAwait(false);
    }

    /// <summary>
    /// Refreshes trending content from SRF API using Play v3.
    /// Gets videos from shows with the most episodes.
    /// </summary>
    /// <param name="businessUnit">The business unit to fetch content for (e.g. "srf", "rts").</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>List of URNs for trending content.</returns>
    public async Task<List<string>> RefreshTrendingContentAsync(string businessUnit, CancellationToken cancellationToken)
    {
        var config = Plugin.Instance?.Configuration;
        if (config == null || !config.EnableTrendingContent)
        {
            _logger.LogDebug("Trending content refresh is disabled");
            return new List<string>();
        }

        return await FetchVideosFromShowsAsync(
            businessUnit,
            minEpisodeCount: 10,
            maxShows: 15,
            videosPerShow: 2,
            contentType: "trending",
            cancellationToken).ConfigureAwait(false);
    }

    /// <summary>
    /// Fetches videos from shows based on filter criteria.
    /// </summary>
    private async Task<List<string>> FetchVideosFromShowsAsync(
        string businessUnit,
        int minEpisodeCount,
        int maxShows,
        int videosPerShow,
        string contentType,
        CancellationToken cancellationToken)
    {
        var urns = new List<string>();

        try
        {
            _logger.LogInformation("Refreshing {ContentType} content for business unit: {BusinessUnit}", contentType, businessUnit);

            using var apiClient = _apiClientFactory.CreateClient();
            var shows = await apiClient.GetAllShowsAsync(businessUnit, cancellationToken).ConfigureAwait(false);

            if (shows == null || shows.Count == 0)
            {
                _logger.LogWarning("No shows found for business unit: {BusinessUnit}", businessUnit);
                return urns;
            }

            _logger.LogInformation("Found {Count} shows, fetching {ContentType} content", shows.Count, contentType);

            var filteredShows = shows
                .Where(s => s.NumberOfEpisodes > minEpisodeCount)
                .OrderByDescending(s => s.NumberOfEpisodes)
                .Take(maxShows)
                .ToList();

            var now = DateTime.UtcNow;

            foreach (var show in filteredShows)
            {
                if (show.Id == null || cancellationToken.IsCancellationRequested)
                {
                    continue;
                }

                try
                {
                    var videos = await apiClient.GetVideosForShowAsync(businessUnit, show.Id, cancellationToken).ConfigureAwait(false);
                    if (videos == null || videos.Count == 0)
                    {
                        _logger.LogDebug("Show {Show} ({ShowId}): No videos returned from API", show.Title, show.Id);
                        continue;
                    }

                    _logger.LogDebug("Show {Show} ({ShowId}): Found {Count} videos", show.Title, show.Id, videos.Count);

                    // Filter to videos that are actually published (validFrom in the past)
                    var publishedVideos = videos
                        .Where(v => v.ValidFrom == null || v.ValidFrom.Value.ToUniversalTime() <= now)
                        .OrderByDescending(v => v.Date)
                        .Take(videosPerShow)
                        .ToList();

                    foreach (var video in publishedVideos)
                    {
                        if (video.Urn != null)
                        {
                            urns.Add(video.Urn);
                            _logger.LogDebug(
                                "Added {ContentType} video from show {Show}: {Title} (URN: {Urn})",
                                contentType,
                                show.Title,
                                video.Title,
                                video.Urn);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Error fetching videos for show {ShowId}", show.Id);
                }
            }

            _logger.LogInformation("Refreshed {Count} {ContentType} content items from {ShowCount} shows", urns.Count, contentType, filteredShows.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error refreshing {ContentType} content", contentType);
        }

        return urns;
    }
}
