using Concilium.Helpers;
using IrcDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Concilium.Bot.Features
{
    [BotFeature(".lastjoin")]
    [BotFeature(".lastpart")]
    [BotFeature(".lastwrite")]
    public class UserMonitorFeature : BotFeatureBase
    {
        public override void Load()
        {
            m_Timer = new Timer(UserMonitorTimerStart, this, 0, 1000);
        }

        private void UserMonitorTimerStart(object state)
        {
            foreach (var channelUser in Concilium.Data.ChannelUsers)
            {
                var channelName = channelUser.Key;
                var users = channelUser.Value.ToList();
                IrcChannel channel;

                if ((channel = Client.Channels.FirstOrDefault(c => c.Name == channelName)) != null)
                {
                    foreach (var nickName in users)
                    {
                        if (!channel.Users.Any(u => u.User.NickName == nickName))
                        {
                            if (!Concilium.Data.Info.ContainsKey(nickName))
                                Concilium.Data.Info[nickName] = new UserInfo();

                            Concilium.Data.Info[nickName].LastLeft = DateTime.Now;
                            Log.Get().Info(string.Format("{0} just left {1}", nickName, channelName));
                            channelUser.Value.Remove(nickName);
                        }
                    }

                    foreach (var userNick in channel.Users)
                    {
                        if (!users.Any(u => u == userNick.User.NickName))
                        {
                            if (!Concilium.Data.Info.ContainsKey(userNick.User.NickName))
                                Concilium.Data.Info[userNick.User.NickName] = new UserInfo();

                            Concilium.Data.Info[userNick.User.NickName].LastJoined = DateTime.Now;
                            Log.Get().Info(string.Format("{0} just joined {1}", userNick, channelName));
                            channelUser.Value.Add(userNick.User.NickName);
                            userNick.User.PropertyChanged += (s, e) =>
                            {
                                if (e.PropertyName == "HostName")
                                {
                                    OnJoin(userNick);
                                }
                            };
                            userNick.User.WhoIs();
                        }
                    }
                }
            }
        }

        private void OnJoin(IrcChannelUser userNick)
        {
            var whitelist = new string[]
            {
                "mirlix",
                "xTr1m",
                "BlueCobold",
                "Daeva",
                "dcu",
                "eXpl0it3r",
                "Lightkey",
                "MasterQ32",
                "Melan",
                "Paprikachu",
                "Socke",
                "Sofa",
                "Schorsch",
                "Nimelrian",
                "ompf",
                "Yatekii",
                "Marrrk",
                "Marrrrk"
            };

            foreach (var nick in whitelist)
            {
                if (userNick.User.NickName.StartsWith(nick, StringComparison.InvariantCultureIgnoreCase) || userNick.User.NickName.EndsWith(nick, StringComparison.InvariantCultureIgnoreCase))
                {
                    if (!userNick.Modes.Contains('v'))
                    {
                        userNick.Voice();
                    }

                    return;
                }
            }

            // Auto-kick:
            //////////////////////////////////////////////////////////////////////
            bool bBlackList = false;

            // Kitty
            bBlackList |= (userNick.User.NickName.ToLowerInvariant().Contains("kitty") || userNick.User.HostName.Contains("dyn.telefonica.de"));

            if (bBlackList)
            {
                userNick.Kick("black listed");
            }
        }

        public override void Execute(string _sCommand, string _sSource, string _sTarget, string _sMessage, IList<string> _parameters, string _ip)
        {
            if (_parameters.Count != 1)
                throw new InvalidCommandParametersException(_sCommand, 1);

            string sParameter = _parameters.First();
            string sReply = null;
            if (!Concilium.Data.Info.ContainsKey(sParameter))
            {
                sReply = string.Format("I have no information about {0} :(", sParameter);
            }
            else
            {
                if (_sCommand == ".lastjoin")
                    sReply = ProcessChatLastJoin(_sSource, _sMessage, sParameter);
                else if (_sCommand == ".lastpart")
                    sReply = ProcessChatLastPart(_sSource, _sMessage, sParameter);
                else if (_sCommand == ".lastwrite")
                    sReply = ProcessChatLastWrite(_sSource, _sMessage, sParameter);
                else
                    throw new NotImplementedException();
            }

            Client.LocalUser.SendMessage(Concilium.GetDefaultReplyTarget(_sSource, _sTarget), sReply);
        }

        private string ProcessChatLastJoin(string _sSource, string _sMessage, string _sParameter)
        {
            if (!Concilium.Data.Info[_sParameter].LastJoined.HasValue)
            {
                return string.Format("{0} joined before I did", _sParameter);
            }
            else
            {
                return string.Format("{0}'s last join date was: {1}", _sParameter, Concilium.Data.Info[_sParameter].LastJoined.Value);
            }
        }

        private string ProcessChatLastPart(string _sSource, string _sMessage, string _sParameter)
        {
            if (!Concilium.Data.Info[_sParameter].LastLeft.HasValue)
            {
                return string.Format("I didn't witness {0} leaving", _sParameter);
            }
            else
            {
                return string.Format("{0} left: {1}", _sParameter, Concilium.Data.Info[_sParameter].LastLeft.Value);
            }
        }

        private string ProcessChatLastWrite(string _sSource, string _sMessage, string _sParameter)
        {
            if (!Concilium.Data.Info[_sParameter].LastWritten.HasValue)
            {
                return string.Format("I've not seen any text from {0}", _sParameter);
            }
            else
            {
                return string.Format("{0}'s last message was on: {1}", _sParameter, Concilium.Data.Info[_sParameter].LastWritten.Value);
            }
        }

        private Timer m_Timer;
    }
}
