using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.SRFPlay.Api;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;

namespace Jellyfin.Plugin.SRFPlay.Services;

/// <summary>
/// Service for managing content expiration.
/// </summary>
public class ContentExpirationService
{
    private readonly ILogger<ContentExpirationService> _logger;
    private readonly ILoggerFactory _loggerFactory;
    private readonly ILibraryManager _libraryManager;
    private readonly StreamUrlResolver _streamResolver;
    private readonly MetadataCache _metadataCache;

    /// <summary>
    /// Initializes a new instance of the <see cref="ContentExpirationService"/> class.
    /// </summary>
    /// <param name="loggerFactory">The logger factory.</param>
    /// <param name="libraryManager">The library manager.</param>
    /// <param name="streamResolver">The stream URL resolver.</param>
    /// <param name="metadataCache">The metadata cache.</param>
    public ContentExpirationService(
        ILoggerFactory loggerFactory,
        ILibraryManager libraryManager,
        StreamUrlResolver streamResolver,
        MetadataCache metadataCache)
    {
        _loggerFactory = loggerFactory;
        _logger = loggerFactory.CreateLogger<ContentExpirationService>();
        _libraryManager = libraryManager;
        _streamResolver = streamResolver;
        _metadataCache = metadataCache;
    }

    /// <summary>
    /// Checks for expired content and removes it from the library.
    /// </summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>The number of items removed.</returns>
    public async Task<int> CheckAndRemoveExpiredContentAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Starting content expiration check");
        var removedCount = 0;

        try
        {
            // Get all items with SRF provider ID
            var query = new InternalItemsQuery
            {
                HasAnyProviderId = new Dictionary<string, string> { { "SRF", string.Empty } },
                IsVirtualItem = false
            };

            var items = _libraryManager.GetItemList(query);
            _logger.LogDebug("Found {Count} SRF items to check for expiration", items.Count);

            foreach (var item in items)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    if (await IsItemExpiredAsync(item, cancellationToken).ConfigureAwait(false))
                    {
                        _logger.LogInformation("Removing expired item: {Name} (URN: {Urn})", item.Name, item.ProviderIds.GetValueOrDefault("SRF"));

                        // Delete the item from library
                        _libraryManager.DeleteItem(
                            item,
                            new DeleteOptions
                            {
                                DeleteFileLocation = false
                            },
                            false);

                        removedCount++;
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error checking expiration for item: {Name}", item.Name);
                }
            }

            _logger.LogInformation("Content expiration check completed. Removed {Count} expired items", removedCount);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during content expiration check");
        }

        return removedCount;
    }

    /// <summary>
    /// Checks if an item is expired.
    /// </summary>
    /// <param name="item">The item to check.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>True if the item is expired.</returns>
    private async Task<bool> IsItemExpiredAsync(BaseItem item, CancellationToken cancellationToken)
    {
        var urn = item.ProviderIds.GetValueOrDefault("SRF");
        if (string.IsNullOrEmpty(urn))
        {
            return false;
        }

        var config = Plugin.Instance?.Configuration;
        if (config == null)
        {
            return false;
        }

        // Try cache first
        var mediaComposition = _metadataCache.GetMediaComposition(urn, config.CacheDurationMinutes);

        // If not in cache, fetch from API
        if (mediaComposition == null)
        {
            using var apiClient = new SRFApiClient(_loggerFactory);
            mediaComposition = await apiClient.GetMediaCompositionByUrnAsync(urn, cancellationToken).ConfigureAwait(false);

            if (mediaComposition != null)
            {
                _metadataCache.SetMediaComposition(urn, mediaComposition);
            }
        }

        if (mediaComposition?.ChapterList == null || mediaComposition.ChapterList.Count == 0)
        {
            // If we can't fetch the content, consider it expired
            _logger.LogWarning("Could not fetch media composition for URN: {Urn}, treating as expired", urn);
            return true;
        }

        var chapter = mediaComposition.ChapterList[0];
        var isExpired = _streamResolver.IsContentExpired(chapter);

        if (isExpired)
        {
            _logger.LogDebug("Item {Name} is expired (ValidTo: {ValidTo})", item.Name, chapter.ValidTo);
        }

        return isExpired;
    }

    /// <summary>
    /// Gets statistics about content expiration.
    /// </summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>Tuple with total count, expired count, and items expiring soon.</returns>
    public async Task<(int Total, int Expired, int ExpiringSoon)> GetExpirationStatisticsAsync(CancellationToken cancellationToken)
    {
        var total = 0;
        var expired = 0;
        var expiringSoon = 0;
        var soonThreshold = DateTime.UtcNow.AddDays(7); // Items expiring within 7 days

        try
        {
            var query = new InternalItemsQuery
            {
                HasAnyProviderId = new Dictionary<string, string> { { "SRF", string.Empty } },
                IsVirtualItem = false
            };

            var items = _libraryManager.GetItemList(query);
            total = items.Count;

            foreach (var item in items)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    var urn = item.ProviderIds.GetValueOrDefault("SRF");
                    if (string.IsNullOrEmpty(urn))
                    {
                        continue;
                    }

                    var config = Plugin.Instance?.Configuration;
                    if (config == null)
                    {
                        continue;
                    }

                    var mediaComposition = _metadataCache.GetMediaComposition(urn, config.CacheDurationMinutes);

                    if (mediaComposition == null)
                    {
                        using var apiClient = new SRFApiClient(_loggerFactory);
                        mediaComposition = await apiClient.GetMediaCompositionByUrnAsync(urn, cancellationToken).ConfigureAwait(false);

                        if (mediaComposition != null)
                        {
                            _metadataCache.SetMediaComposition(urn, mediaComposition);
                        }
                    }

                    if (mediaComposition?.ChapterList != null && mediaComposition.ChapterList.Count > 0)
                    {
                        var chapter = mediaComposition.ChapterList[0];

                        if (_streamResolver.IsContentExpired(chapter))
                        {
                            expired++;
                        }
                        else if (chapter.ValidTo.HasValue && chapter.ValidTo.Value.ToUniversalTime() <= soonThreshold)
                        {
                            expiringSoon++;
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error checking expiration statistics for item: {Name}", item.Name);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting expiration statistics");
        }

        return (total, expired, expiringSoon);
    }
}
