using Microsoft.Extensions.Logging;
using System.Text;
using YoutubeExplode;
using YoutubeExplode.Videos;
using YoutubeExplode.Videos.ClosedCaptions;

namespace YTExtractor.Services.YoutubeExplode
{
    /// <summary>
    /// Client using the YoutubeExplode library to extract data from YouTube
    /// </summary>
    public class YoutubeExplodeClient
    {
        private readonly ILogger<YoutubeExplodeClient> _logger;
        private readonly YoutubeClient _youtube;

        public YoutubeExplodeClient(ILogger<YoutubeExplodeClient> logger)
        {
            _logger = logger;
            _youtube = new YoutubeClient();
        }

        /// <summary>
        /// Gets video information from a YouTube URL
        /// </summary>
        /// <param name="url">The YouTube video URL</param>
        /// <returns>Video information or null if it fails</returns>
        public async Task<YtDlpInfo?> GetVideoInfoAsync(string url)
        {
            try
            {
                _logger.LogInformation("Getting video info using YoutubeExplode for {Url}", url);
                
                // Get the video ID from the URL
                var videoId = VideoId.TryParse(url);
                if (videoId == null)
                {
                    _logger.LogWarning("Invalid YouTube URL: {Url}", url);
                    return null;
                }

                // Get the video metadata
                var video = await _youtube.Videos.GetAsync(videoId.Value);
                
                return new YtDlpInfo(
                    video.Title,
                    video.Thumbnails.LastOrDefault()?.Url ?? ""
                );
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting video info with YoutubeExplode for {Url}", url);
                return null;
            }
        }

        /// <summary>
        /// Gets subtitles for a YouTube video
        /// </summary>
        /// <param name="url">The YouTube video URL</param>
        /// <param name="language">The language code (e.g., "en", "pt")</param>
        /// <returns>The subtitle content or null if it fails</returns>
        public async Task<string?> GetSubtitlesAsync(string url, string language)
        {
            try
            {
                _logger.LogInformation("Getting subtitles using YoutubeExplode for {Url} in language {Language}", url, language);
                
                // Get the video ID from the URL
                var videoId = VideoId.TryParse(url);
                if (videoId == null)
                {
                    _logger.LogWarning("Invalid YouTube URL: {Url}", url);
                    return null;
                }

                // Get the closed caption tracks available for the video
                var trackManifest = await _youtube.Videos.ClosedCaptions.GetManifestAsync(videoId.Value);
                
                // Find the track for the requested language
                var trackInfo = trackManifest.GetByLanguage(language);
                if (trackInfo == null)
                {
                    // If not found, try to find an auto-generated track for the language
                    trackInfo = trackManifest.Tracks
                        .FirstOrDefault(t => t.Language.Code == language && t.IsAutoGenerated);
                        
                    if (trackInfo == null)
                    {
                        _logger.LogWarning("No subtitles found for language {Language} for video {Url}", language, url);
                        return null;
                    }
                }
                
                // Get the actual captions
                var track = await _youtube.Videos.ClosedCaptions.GetAsync(trackInfo);
                
                // Convert the captions to WebVTT format
                var vttBuilder = new StringBuilder();
                vttBuilder.AppendLine("WEBVTT");
                vttBuilder.AppendLine();
                
                foreach (var caption in track.Captions)
                {
                    var startTime = FormatTime(caption.Offset);
                    var endTime = FormatTime(caption.Offset + caption.Duration);
                    
                    vttBuilder.AppendLine($"{startTime} --> {endTime}");
                    vttBuilder.AppendLine(caption.Text);
                    vttBuilder.AppendLine();
                }
                
                return vttBuilder.ToString();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting subtitles with YoutubeExplode for {Url} in language {Language}", url, language);
                return null;
            }
        }
        
        /// <summary>
        /// Format TimeSpan as WebVTT time format (HH:MM:SS.mmm)
        /// </summary>
        private string FormatTime(TimeSpan time)
        {
            return $"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2}.{time.Milliseconds:D3}";
        }
    }
}