using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Argotic.Common;
using Argotic.Syndication;
using SharpRss.Models;
using ToolQit;
using ToolQit.Logging;

namespace SharpRss.Services
{
    /// <summary>
    /// Managing syndication feeds and categories.
    /// </summary>
    public class SyndicationService
    {
        private readonly ILog _log;
        public SyndicationService()
        {
            _log = LogManager.CreateLogger(typeof(SyndicationService));
            _log.Information("Constructing SyndicationService...");
            Task.Run(async () => await SetupTestCategoriesAndFeedsAsync());
        }

        public async Task<HashSet<object>> GetCategoriesAndSyndicationsAsync()
        {
            HashSet<object> items = new HashSet<object>();
            items.UnionWith(await GetCategoriesAsync());
            items.UnionWith(await GetUngroupedSyndicationsAsync());
            return items;
        }

        public async Task<CategoryModel?> CreateCategoryAsync(CategoryModel category) =>
            await DbAccess.SetCategoryAsync(category);

        public async Task<HashSet<CategoryModel>> GetCategoriesAsync()
        {
            HashSet<CategoryModel> categories = await DbAccess.GetCategoriesAsync();
            foreach (CategoryModel catModel in categories)
            {
                catModel.Syndications = await DbAccess.GetSyndicationsAsync(new[] { catModel.Id });
            }
            return categories;
        }

        private async void ForEachCategories(CategoryModel x) => x.Syndications = await DbAccess.GetSyndicationsAsync(new[] { x.Id });

        public async Task<bool> AddSubscriptionAsync(string url, CategoryModel? category = null)
        {
            var syndication = SyndicationManager.CreateSyndication(url);
            if (!syndication.Fetched)
            {
                _log.Warning("Failed to fetch syndication feed!");
                return false;
            }
            if (category != null)
                syndication.Category = category;
            try
            {
                await DbAccess.SetSyndicationAsync(syndication);
            }
            catch (Exception e)
            {
                _log.Error(e,"Error adding syndication: {FeedUrl} to database!", url);
            }
            return true;
        }
        public async Task UpdateFeeds()
        {
            _log.Information("Fetching...");
            var feeds = await GetSyndicationsAsync();
        }
        public async Task<HashSet<SyndicationModel>> GetSyndicationsAsync(string? categoryId = null) => await DbAccess.GetSyndicationsAsync(categoryId == null ? null : new[]{ categoryId });
        public async Task<HashSet<SyndicationModel>> GetUngroupedSyndicationsAsync() => await DbAccess.GetSyndicationsAsync(new []{""});
        public async Task<HashSet<SyndicationItemModel>> GetSyndicationItemsAsync(string feedId, string? groupId = null) => await GetSyndicationItemsFromSyndicationsAsync(new[] { feedId }, groupId);
        public async Task<HashSet<SyndicationItemModel>> GetSyndicationItemsFromSyndicationsAsync(string[] feedIds, string? categoryId = null)
        {
            /*var items =  await DbAccess.GetSyndicationItemsAsync(feedIds);
            return items;*/
            return new HashSet<SyndicationItemModel>();
        }
        
        
        
        /*private static SyndicationModel FromResource(ISyndicationResource resource)
        {
            SyndicationModel model = new SyndicationModel();
            switch (resource.Format)
            {
                case SyndicationContentFormat.Rss:
                    RssFeed rssFeed = (RssFeed)resource;
                    model.SyndicationType = rssFeed.Format.ToString();
                    model.Title = rssFeed.Channel.Title;
                    model.Description = rssFeed.Channel.Description;
                    model.Copyright = rssFeed.Channel.Copyright;
                    model.EncodedUrl = rssFeed.Channel.SelfLink.ToString();
                    model.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty;
                    model.Language = rssFeed.Channel.Language?.ToString();
                    break;
                case SyndicationContentFormat.Atom:
                    AtomFeed atomFeed = (AtomFeed)resource;
                    break;
                default:
                    _log.Information("Syndication implementation missing!");
                    break;
            }
            return model;
        }*/
        private GenericSyndicationFeed? CreateSyndication(string url)
        {
            Uri feedUri = new Uri(url);
            _log.Verbose("Checking syndication: {FeedUrl}", feedUri.ToString());
            if (!SyndicationDiscoveryUtility.UriExists(feedUri))
            {
                _log.Warning("Syndication: {FeedUri} does not exists!", feedUri.ToString());
                return null;
            }
            _log.Verbose("Fetching syndication: {FeedUrl}", feedUri.ToString());
            return GenericSyndicationFeed.Create(new Uri(url));
        }
        private async Task SetupTestCategoriesAndFeedsAsync()
        {
            _log.Information("Setting up test data...");
            try
            {
                CategoryModel? newsCategory = await CreateCategoryAsync(new CategoryModel() { Name = "News", Icon = "<g><rect fill=\"none\" height=\"24\" width=\"24\"/></g><g><path d=\"M22,3l-1.67,1.67L18.67,3L17,4.67L15.33,3l-1.66,1.67L12,3l-1.67,1.67L8.67,3L7,4.67L5.33,3L3.67,4.67L2,3v16 c0,1.1,0.9,2,2,2l16,0c1.1,0,2-0.9,2-2V3z M11,19H4v-6h7V19z M20,19h-7v-2h7V19z M20,15h-7v-2h7V15z M20,11H4V8h16V11z\"/></g>"});
                if (newsCategory != null)
                {
                    await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen", newsCategory);
                    await AddSubscriptionAsync("https://www.ad.nl/home/rss.xml", newsCategory);
                    await AddSubscriptionAsync("https://www.nasa.gov/rss/dyn/breaking_news.rss", newsCategory);
                    await AddSubscriptionAsync("http://news.google.com/?output=atom", newsCategory);
                }
                
                CategoryModel? techCategory = await CreateCategoryAsync(new CategoryModel() { Name = "Tech", Icon = "<g><rect fill=\"none\" height=\"24\" width=\"24\"/></g><g><path d=\"M17,10.43V2H7v8.43c0,0.35,0.18,0.68,0.49,0.86l4.18,2.51l-0.99,2.34l-3.41,0.29l2.59,2.24L9.07,22L12,20.23L14.93,22 l-0.78-3.33l2.59-2.24l-3.41-0.29l-0.99-2.34l4.18-2.51C16.82,11.11,17,10.79,17,10.43z M13,12.23l-1,0.6l-1-0.6V3h2V12.23z\"/></g>"});
                if (techCategory != null)
                {
                    await AddSubscriptionAsync("https://itsfoss.com/feed", techCategory);
                    await AddSubscriptionAsync("http://fedoramagazine.org/feed/", techCategory);
                    await AddSubscriptionAsync("https://arstechnica.com/feed/", techCategory);
                    await AddSubscriptionAsync("https://feeds.arstechnica.com/arstechnica/gadgets", techCategory);
                }

                CategoryModel? youtubeCategory = await CreateCategoryAsync(new CategoryModel() { Name = "YouTube", Icon = "<path d=\"M10 15l5.19-3L10 9v6m11.56-7.83c.13.47.22 1.1.28 1.9.07.8.1 1.49.1 2.09L22 12c0 2.19-.16 3.8-.44 4.83-.25.9-.83 1.48-1.73 1.73-.47.13-1.33.22-2.65.28-1.3.07-2.49.1-3.59.1L12 19c-4.19 0-6.8-.16-7.83-.44-.9-.25-1.48-.83-1.73-1.73-.13-.47-.22-1.1-.28-1.9-.07-.8-.1-1.49-.1-2.09L2 12c0-2.19.16-3.8.44-4.83.25-.9.83-1.48 1.73-1.73.47-.13 1.33-.22 2.65-.28 1.3-.07 2.49-.1 3.59-.1L12 5c4.19 0 6.8.16 7.83.44.9.25 1.48.83 1.73 1.73z\"/>"});
                if (youtubeCategory != null)
                {
                    await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UCXuqSBlHAE6Xw-yeJA0Tunw", youtubeCategory);
                    await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UC1Et9K-hHf-P_LzQkE_Q3Jw", youtubeCategory);
                    await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UCsXVk37bltHxD1rDPwtNM8Q", youtubeCategory);
                }
            
                await AddSubscriptionAsync("http://www.digitaleoverheid.nl/feed/");
                await AddSubscriptionAsync("http://www.digitaleoverheid.nl/agenda/feed/");
                await AddSubscriptionAsync("https://feeds.rijksoverheid.nl/nieuws.rss");
                await AddSubscriptionAsync("https://nl.wikipedia.org/w/index.php?title=Speciaal:RecenteWijzigingen&feed=atom");
                await AddSubscriptionAsync("https://feeds.aivd.nl/nieuws.rss");
                await AddSubscriptionAsync("https://blogs.microsoft.com/feed");
                await AddSubscriptionAsync("https://www.europarl.europa.eu/rss/doc/top-stories/nl.xml");
            }
            catch (Exception e)
            {
                _log.Error(e, "Exception!");
            }
        }
    }
}