using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Text;
using System.Threading;
using System.Xml;

namespace Concilium.Bot.Features
{
    [BotFeature(".rssadd")]
    [BotFeature(".rssdel")]
    [BotFeature(".rsslist")]
    public class RssFeature : BotFeatureBase
    {
        public override void Load()
        {
            m_Timer = new Timer(RssTimerStart, this, 0, 60000);
        }

        private void RssTimerStart(object state)
        {
            if (Concilium.Data == null)
                return;

            foreach (var nickName in Concilium.Data.Info.Keys.ToList())
            {
                if (Concilium.Data.Info[nickName].SubscribedFeeds != null)
                {
                    foreach (var feed in Concilium.Data.Info[nickName].SubscribedFeeds.ToList())
                    {
                        try
                        {
                            var reader = XmlReader.Create(feed.Url);
                            var synFeed = SyndicationFeed.Load(reader);

                            var newList = new List<RssItem>();
                            foreach (SyndicationItem i in synFeed.Items)
                            {
                                newList.Add(new RssItem() { Link = i.Links[0].Uri.ToString(), Title = i.Title.Text });
                            }

                            foreach (var item in newList)
                            {
                                if (feed.LastItems != null && feed.LastItems.Any(li => li.Link == item.Link))
                                    continue;

                                Client.LocalUser.SendMessage(nickName, string.Format("{0} {1}", item.Title, item.Link));
                            }

                            feed.LastItems = newList;
                        }
                        catch (Exception e)
                        {
                            Client.LocalUser.SendNotice(nickName, string.Format("Error while checking {0}: {1}", feed.Url, e.Message));
                        }
                    }
                }
            }
        }

        public override void Execute(string _sCommand, string _sSource, string _sTarget, string _sMessage, IList<string> _parameters, string _ip)
        {
            if (_sCommand == ".rssadd")
                ProcessChatRssAdd(_sSource, _sMessage, _parameters);
            else if (_sCommand == ".rssdel")
                ProcessChatRssAdd(_sSource, _sMessage, _parameters);
            else if (_sCommand == ".rsslist")
                ProcessChatRssAdd(_sSource, _sMessage, _parameters);
            else 
                throw new NotImplementedException();
        }

        private void ProcessChatRssAdd(string _sSource, string _sMessage, IList<string> _parameters)
        {
            if (_parameters.Count != 1)
                throw new InvalidCommandParametersException(".rssadd", 1);

            try
            {
                XmlReader reader = XmlReader.Create(_parameters[0], new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse });
                SyndicationFeed synFeed = SyndicationFeed.Load(reader);

                if (Concilium.Data.Info[_sSource].SubscribedFeeds == null)
                    Concilium.Data.Info[_sSource].SubscribedFeeds = new List<RssFeed>();

                if (!Concilium.Data.Info[_sSource].SubscribedFeeds.Any(f => f.Url == _parameters[0]))
                {
                    Concilium.Data.Info[_sSource].SubscribedFeeds.Add(new RssFeed() { Url = _parameters[0], LastItems = new List<RssItem>() });
                    Client.LocalUser.SendMessage(_sSource, "RSS feed subscribed successfully");
                }
                else
                {
                    Client.LocalUser.SendMessage(_sSource, "RSS feed already subscribed");
                }
            }
            catch (Exception)
            {
                Client.LocalUser.SendMessage(_sSource, "Error: RSS feed not recognized");
            }
        }

        private void ProcessChatRssDel(string _sSource, string _sMessage, IList<string> _parameters)
        {
            if (_parameters.Count != 1)
                throw new InvalidCommandParametersException(".rssdel", 1);

            if (Concilium.Data.Info[_sSource].SubscribedFeeds == null)
            {
                Client.LocalUser.SendMessage(_sSource, "RSS feed doesn't exist");
            }
            else
            {
                var rssFeed = Concilium.Data.Info[_sSource].SubscribedFeeds.FirstOrDefault(f => f.Url == _parameters[0]);
                if (rssFeed != null)
                {
                    Concilium.Data.Info[_sSource].SubscribedFeeds.Remove(rssFeed);
                    Client.LocalUser.SendMessage(_sSource, "RSS feed removed successfully");
                }
                else
                {
                    Client.LocalUser.SendMessage(_sSource, "RSS feed doesn't exist");
                }
            }
        }

        private void ProcessChatRssList(string _sSource, string _sMessage, IList<string> _parameters)
        {
            if (_parameters.Count != 0)
                throw new InvalidCommandParametersException(".rsslist", 0);

            Client.LocalUser.SendMessage(_sSource, "Currently subscribed RSS feeds:");
            if (Concilium.Data.Info[_sSource].SubscribedFeeds == null || Concilium.Data.Info[_sSource].SubscribedFeeds.Count == 0)
                Client.LocalUser.SendMessage(_sSource, "(none)");
            else foreach (var rssFeed in Concilium.Data.Info[_sSource].SubscribedFeeds)
                {
                    Client.LocalUser.SendMessage(_sSource, rssFeed.Url);
                }
        }

        private Timer m_Timer;
    }
}
