using Aberwyn.Data;
using Aberwyn.Models;
using Microsoft.EntityFrameworkCore;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace Aberwyn.Data
{
    public class RssProcessor : IRssProcessor
    {
        private readonly ApplicationDbContext _context;
        private readonly ILogger<RssProcessor> _logger;
        private readonly HttpClient _httpClient;
        private readonly HdTorrentsTrackerScraper _trackerScraper;
        private readonly MovieMetadataService _movieMetadataService;

        public RssProcessor(ApplicationDbContext context, ILogger<RssProcessor> logger,
                           HttpClient httpClient, HdTorrentsTrackerScraper trackerScraper, MovieMetadataService movieMetadataService)
        {
            _context = context;
            _logger = logger;
            _httpClient = httpClient;
            _trackerScraper = trackerScraper;
            _movieMetadataService = movieMetadataService;
        }

        public async Task ProcessRssFeeds()
        {

            var debug = false;
            
            var oneHourAgo = DateTime.UtcNow.AddHours(-1);
            if (debug)
                oneHourAgo = DateTime.UtcNow.AddHours(1);
            
            var activeFeeds = await _context.RssFeeds
                 .Where(f => f.IsActive && f.LastChecked <= oneHourAgo)
                .ToListAsync();

            foreach (var feed in activeFeeds)
            {
                try
                {
                    await ProcessSingleFeed(feed);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error processing RSS feed {FeedName}", feed.Name);
                }
            }
        }

        private async Task ProcessSingleFeed(RssFeed feed)
        {
            var rssContent = await _httpClient.GetStringAsync(feed.Url);
            var rssDoc = XDocument.Parse(rssContent);
            var items = rssDoc.Descendants("item");
            try
            {
                foreach (var item in items)
                {
                    try
                    {
                        var torrentItem = ParseRssItem(item, feed);
                        Console.WriteLine($"Trying to save: Title='{torrentItem.Title}', InfoHash='{torrentItem.InfoHash}', MovieName='{torrentItem.MovieName}'");

                        // Kolla om den redan finns
                        var exists = await _context.TorrentItems
                            .AnyAsync(t => t.InfoHash == torrentItem.InfoHash ||
                                          (t.Title == torrentItem.Title && t.RssSource == feed.Name));


                        if (!exists)
                        {
                            if (!string.IsNullOrEmpty(torrentItem.InfoHash) && !string.IsNullOrEmpty(torrentItem.DownloadKey))
                            {
                                var (seeders, leechers, completed) = await _trackerScraper.ScrapeHdTorrents(
                                    torrentItem.InfoHash,
                                    torrentItem.DownloadKey);

                                torrentItem.Seeders = seeders;
                                torrentItem.Leechers = leechers;
                                torrentItem.Completed = completed;

                                Console.WriteLine($"Scraped stats for {torrentItem.Title}: S:{seeders} L:{leechers} C:{completed}");
                            }
                            
                            var metadata = await _movieMetadataService.GetMovieAsync(torrentItem.MovieName, torrentItem.Year);
                            if (metadata != null)
                            {
                                torrentItem.Metadata = metadata;
                                var tmdbService = new TmdbService();
                                torrentItem.Metadata.Providers = await tmdbService.GetWatchProvidersByTitleAsync(torrentItem.MovieName, torrentItem.Year);

                            }

                            _context.TorrentItems.Add(torrentItem);
                            var savedChanges = await _context.SaveChangesAsync();
                            Console.WriteLine($"SaveChanges returned: {savedChanges}");
                            // Kolla auto-download regler
                            if (await ShouldAutoDownload(torrentItem))
                            {
                                await ProcessTorrentDownload(torrentItem);
                            }
                        } else
                        {

                            var howLongAgo = DateTime.UtcNow.AddHours(-6);
                            if (torrentItem.PublishDate >= howLongAgo)
                            {

                                var existing = await _context.TorrentItems
                                .FirstOrDefaultAsync(t => t.InfoHash == torrentItem.InfoHash
                                                       || (t.Title == torrentItem.Title && t.RssSource == feed.Name));

                                if (existing != null)
                                {
                                    var (seeders, leechers, completed) = await _trackerScraper.ScrapeHdTorrents(
                                        existing.InfoHash,
                                        existing.DownloadKey);

                                    existing.Seeders = seeders;
                                    existing.Leechers = leechers;
                                    existing.Completed = completed;

                                    _context.TorrentItems.Update(existing);
                                    await _context.SaveChangesAsync();

                                    Console.WriteLine($"Updated stats for {existing.Title}: S:{seeders} L:{leechers} C:{completed}");
                                }
                            }

                        }
                    }
                    catch (Exception itemEx)
                    {
                        Console.WriteLine($"Error processing individual item: {itemEx.Message}");
                        Console.WriteLine($"Stack trace: {itemEx.StackTrace}");
                    }
                }

                feed.LastChecked = DateTime.UtcNow;
                await _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error in ProcessSingleFeed: {ex.Message}");
                Console.WriteLine($"Stack trace: {ex.StackTrace}");
            }
        }

        private TorrentItem ParseRssItem(XElement item, RssFeed feed)
        {
            var title = item.Element("title")?.Value ?? "Unknown Title";
            var description = item.Element("description")?.Value ?? ""; // Fix: Default till tom sträng
            var pubDate = DateTime.TryParse(item.Element("pubDate")?.Value, out var date) ? date : DateTime.UtcNow;
            var link = item.Element("link")?.Value ?? "";

            var infoHash = ExtractInfoHashFromUrl(link);
            var downloadKey = ExtractParameterFromUrl(link, "key");
            var token = ExtractParameterFromUrl(link, "token");
            var (movieName, year) = ParseMovieNameAndYear(title);

            var magnetLink = "";
            if (!string.IsNullOrEmpty(infoHash))
            {
                magnetLink = $"magnet:?xt=urn:btih:{infoHash}&dn={Uri.EscapeDataString(title)}";
            }

            return new TorrentItem
            {
                Title = title ?? "Unknown Title", // Garanterat inte null
                Description = description ?? string.Empty, // Garanterat inte null  
                TorrentUrl = string.IsNullOrEmpty(link) ? null : link,
                MagnetLink = string.IsNullOrEmpty(magnetLink) ? null : magnetLink,
                InfoHash = string.IsNullOrEmpty(infoHash) ? null : infoHash,
                PublishDate = pubDate,
                RssSource = feed.Name ?? "Unknown", // Garanterat inte null
                Status = TorrentStatus.New,
                DownloadKey = string.IsNullOrEmpty(downloadKey) ? null : downloadKey,
                Token = string.IsNullOrEmpty(token) ? null : token,
                MovieName = string.IsNullOrEmpty(movieName) ? null : movieName,
                Year = year,
                Category = DetermineCategory(title),
                CreatedAt = DateTime.UtcNow
            };
        }

        private (string movieName, int? year) ParseMovieNameAndYear(string title)
        {
            // Exempel titlar:
            // "Bring It on Fight to the Finish 2009 BluRay 1080p DDP 5.1 x264-hallowed"
            // "Deadpool & Wolverine 2024 Hybrid 1080p UHD BluRay DD+5.1 Atmos DV HDR10+ x265-HiDt"

            var movieName = "";
            int? year = null;

            // Leta efter år (4 siffror mellan 1900-2099)
            var yearMatch = System.Text.RegularExpressions.Regex.Match(title, @"\b(19\d{2}|20\d{2})\b");
            if (yearMatch.Success && int.TryParse(yearMatch.Groups[1].Value, out var parsedYear))
            {
                year = parsedYear;

                // Ta allt före året som filmnamn
                var yearIndex = yearMatch.Index;
                movieName = title.Substring(0, yearIndex).Trim();
            }
            else
            {
                // Om inget år hittas, ta första delen före vanliga release-keywords
                var keywordMatch = System.Text.RegularExpressions.Regex.Match(title,
                    @"\b(BluRay|WEB-DL|WEBRip|HDTV|DVDRIP|REMUX|UHD|1080p|720p|480p|2160p)\b",
                    RegexOptions.IgnoreCase);

                if (keywordMatch.Success)
                {
                    movieName = title.Substring(0, keywordMatch.Index).Trim();
                }
                else
                {
                    // Fallback: ta första delen innan sista bindestreck
                    var lastDashIndex = title.LastIndexOf('-');
                    if (lastDashIndex > 0)
                    {
                        movieName = title.Substring(0, lastDashIndex).Trim();
                    }
                    else
                    {
                        movieName = title;
                    }
                }
            }

            // Rensa bort vanliga suffix från filmnamnet
            movieName = System.Text.RegularExpressions.Regex.Replace(movieName,
                @"\b(REMASTERED|REPACK|PROPER|REAL|EXTENDED|DIRECTORS?\.?CUT|UNRATED)\b",
                "", RegexOptions.IgnoreCase).Trim();

            return (movieName, year);
        }

        private string ExtractInfoHashFromUrl(string url)
        {
            if (string.IsNullOrEmpty(url)) return "";

            var match = System.Text.RegularExpressions.Regex.Match(url, @"hash=([a-fA-F0-9]{40})");
            return match.Success ? match.Groups[1].Value.ToUpper() : "";
        }

        private string ExtractParameterFromUrl(string url, string paramName)
        {
            if (string.IsNullOrEmpty(url)) return "";

            var match = System.Text.RegularExpressions.Regex.Match(url, $@"{paramName}=([^&]+)");
            return match.Success ? Uri.UnescapeDataString(match.Groups[1].Value) : "";
        }

        private string DetermineCategory(string title)
        {
            if (System.Text.RegularExpressions.Regex.IsMatch(title, @"\b(S\d{2}E\d{2}|Season|Episode)\b", RegexOptions.IgnoreCase))
                return "TV";
            else
                return "Movies";
        }

        private async Task<bool> ShouldAutoDownload(TorrentItem item)
        {
            var rules = await _context.DownloadRules.Where(r => r.AutoDownload).ToListAsync();

            return rules.Any(rule =>
                (string.IsNullOrEmpty(rule.KeywordFilter) ||
                 item.Title.Contains(rule.KeywordFilter, StringComparison.OrdinalIgnoreCase)) &&
                (string.IsNullOrEmpty(rule.CategoryFilter) ||
                 item.Category == rule.CategoryFilter) &&
                item.Seeders >= rule.MinSeeders &&
                (rule.MaxSize == 0 || item.Size <= rule.MaxSize));
        }

        private async Task ProcessTorrentDownload(TorrentItem item)
        {
            try
            {
                if (!string.IsNullOrEmpty(item.MagnetLink))
                {
                    _logger.LogInformation("Starting magnet download for {Title}", item.Title);
                    item.Status = TorrentStatus.Downloaded;
                }
                else if (!string.IsNullOrEmpty(item.TorrentUrl))
                {
                    var torrentData = await _httpClient.GetByteArrayAsync(item.TorrentUrl);
                    item.Status = TorrentStatus.Downloaded;
                }

                await _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error downloading torrent {Title}", item.Title);
                item.Status = TorrentStatus.Failed;
                await _context.SaveChangesAsync();
            }
        }
    }
}