using InABox.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;

namespace InABox.Core
{
    public interface IPollHandler
    {
        Type Type { get; }

        /// <summary>
        /// Polls for notifications, called on client connection.
        /// </summary>
        /// <returns>New notifications</returns>
        IEnumerable<object> Poll(Guid session);
    }
    public class PollHandler<TNotification> : IPollHandler
    {
        public delegate IEnumerable<TNotification> PollEvent(Guid session);

        public event PollEvent? OnPoll;

        public Type Type => typeof(TNotification);

        public PollHandler() { }

        public PollHandler(PollEvent poll)
        {
            OnPoll += poll;
        }

        public IEnumerable<object> Poll(Guid session) => (OnPoll?.Invoke(session) ?? Array.Empty<TNotification>()).Cast<object>();
    }


    public abstract class Notifier
    {
        private List<IPollHandler> Handlers = new List<IPollHandler>();

        protected abstract void NotifyAll<TNotification>(TNotification notification);
        protected abstract void NotifySession<TNotification>(Guid session, TNotification notification);
        protected abstract void NotifySession(Guid session, Type TNotification, object? notification);
        protected abstract IEnumerable<Guid> GetUserSessions(Guid user);
        protected abstract IEnumerable<Guid> GetSessions(Platform platform);

        public void Push<TNotification>(TNotification notification)
        {
            NotifyAll(notification);
        }

        public void Push<TNotification>(Guid session, TNotification notification)
        {
            NotifySession(session, notification);
        }
        public void PushUser<TNotification>(Guid user, TNotification notification)
        {
            foreach (var session in GetUserSessions(user))
            {
                NotifySession(session, notification);
            }
        }
        public void Push<TNotification>(Platform platform, TNotification notification)
        {
            foreach (var session in GetSessions(platform))
            {
                NotifySession(session, notification);
            }
        }

        public void Poll(Guid session)
        {
            foreach (var handler in Handlers)
            {
                foreach (var notification in handler.Poll(session))
                {
                    NotifySession(session, handler.Type, notification);
                }
            }
        }

        public void AddPollHandler<TNotification>(PollHandler<TNotification> handler)
        {
            Handlers.Add(handler);
        }
        public void AddPollHandler<TNotification>(PollHandler<TNotification>.PollEvent poll)
        {
            Handlers.Add(new PollHandler<TNotification>(poll));
        }

    }
}