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 pushes, called on client connection.
        /// </summary>
        /// <returns>New pushes</returns>
        IEnumerable<BaseObject> Poll(Guid session);
    }
    public class PollHandler<TPush> : IPollHandler
        where TPush : BaseObject
    {
        public delegate IEnumerable<TPush> PollEvent(Guid session);

        public event PollEvent? OnPoll;

        public Type Type => typeof(TPush);

        public PollHandler() { }

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

        public IEnumerable<BaseObject> Poll(Guid session) => OnPoll?.Invoke(session) ?? Array.Empty<TPush>();
    }

    /// <summary>
    /// Classes that implement this interface implement the manner by which the server actually gets messages pushed to the client.
    /// The implementation will manage the transport layer.
    /// </summary>
    /// <remarks>
    /// If one wishes to implement <see cref="IPusher"/>, it is likely one should also register it with <see cref="PushManager.AddPusher(IPusher)"/>;
    /// this way, when the server wishes to push a message, it will go through this pusher (as well as any other registered ones).
    /// </remarks>
    public interface IPusher
    {
        void PushToAll<TPush>(TPush push) where TPush : BaseObject;
        void PushToSession<TPush>(Guid session, TPush push) where TPush : BaseObject;
        void PushToSession(Guid session, Type TPush, BaseObject push);
        IEnumerable<Guid> GetUserSessions(Guid user);
        IEnumerable<Guid> GetSessions(Platform platform);

        public void Push<TPush>(TPush push)
            where TPush : BaseObject
        {
            PushToAll(push);
        }

        public void Push(Guid session, Type TPush, BaseObject push)
        {
            PushToSession(session, TPush, push);
        }

        public void Push<TPush>(Guid session, TPush push)
            where TPush : BaseObject
        {
            PushToSession(session, push);
        }
        public void PushUser<TPush>(Guid user, TPush push)
            where TPush : BaseObject
        {
            foreach (var session in GetUserSessions(user))
            {
                PushToSession(session, push);
            }
        }
        public void Push<TPush>(Platform platform, TPush push)
            where TPush : BaseObject
        {
            foreach (var session in GetSessions(platform))
            {
                PushToSession(session, push);
            }
        }

    }
}