using System;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Linq;
using Aurora.Utils;
using Aurora.Proto.Party;
using Aurora.Proto.Events;
using Aurora.Services.EventManager;
using Aurora.Services;
using Aurora.Models.Media;

namespace Aurora.RemoteImpl
{
    public class RemotePartyServiceImpl : RemotePartyService.RemotePartyServiceBase
    {
        /// <summary>
        /// Dictionary of party members. Key -> ClientId
        /// </summary>
        private ObservableCollection<PartyMember> _partyMembers;

        public RemotePartyServiceImpl()
        {
            _partyMembers = new ObservableCollection<PartyMember>();
        }

        public ObservableCollection<PartyMember> PartyMembers
        {
            get
            {
                return _partyMembers;
            }
        }

        public override Task<JoinPartyResponse> JoinParty(JoinPartyRequest request, Grpc.Core.ServerCallContext context)
        {
            PartyMember partyMember = new PartyMember("")
            {
                UserName = request.UserName,
                IpAddress = context.Host,
            };

            Console.WriteLine("SERVER - Client joined party: " + partyMember.Id);

            _partyMembers.Add(partyMember);

            BaseEvent e = new BaseEvent
            {
                EventType = EventType.PartyMemberJoined,
                PartyMemberJoinedEvent = new PartyMemberJoinedEvent
                {
                    Member = partyMember,
                }
            };

            EventManager.Instance.FireEvent(e);

            JoinPartyResponse response = new JoinPartyResponse() { Status = PartyJoinedStatusEnum.Connected, ClientId = partyMember.Id };
            return Task.FromResult(response);
        }

        public override Task<LeavePartyResponse> LeaveParty(LeavePartyRequest request, Grpc.Core.ServerCallContext context)
        {
            PartyMember partyMember = _partyMembers.Where(e => e.Id == request.ClientId).Single();

            _partyMembers.Remove(partyMember);

            BaseEvent bv = new BaseEvent
            {
                EventType = EventType.PartyMemberJoined,
                PartyMemberLeftEvent = new PartyMemberLeftEvent
                {
                    Member = partyMember,
                }
            };

            EventManager.Instance.FireEvent(bv);
            EventManager.Instance.RemoveAllSubscriptions(Misc.Combine(new string[] { context.Peer, request.ClientId }));
            EventManager.Instance.CancelEventStream(Misc.Combine(new string[] { context.Peer, request.ClientId }));

            LeavePartyResponse response = new LeavePartyResponse() { Status = PartyJoinedStatusEnum.Disconnected };
            return Task.FromResult(response);
        }

        public override Task<MembersResponse> GetPartyMembers(Proto.General.Empty empty, Grpc.Core.ServerCallContext context)
        {
            MembersResponse response = new MembersResponse();
            response.Members.AddRange(_partyMembers);
            return Task.FromResult(response);
        }

        public override Task<QueueResponse> GetQueue(Proto.General.Empty empty, Grpc.Core.ServerCallContext context)
        {
            //This will change as queuing operation gets solidified
            //Simply return the hosts library

            ObservableCollection<BaseMedia> queue = LibraryService.Instance.GetLibrary();

            QueueResponse mediaList = new QueueResponse();
            foreach (BaseMedia media in queue)
            {
                AudioMetadata metadata = new AudioMetadata();
                try
                {
                    if (media.Metadata is AudioMetadata)
                    {
                        metadata = media.Metadata as AudioMetadata;

                        RemoteMediaData data = new RemoteMediaData();
                        data.Id = media.Id;
                        if (metadata.Title != null)
                        {
                            data.Title = metadata.Title;
                        }
                        if (metadata.Artist != null)
                        {
                            data.Artist = metadata.Artist;
                        }
                        if (metadata.Album != null)
                        {
                            data.Album = metadata.Album;
                        }
                        if (metadata.Duration != null)
                        {
                            data.Duration = metadata.Duration;
                        }

                        mediaList.MediaList.Add(data);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Error preparing queue: {0}", ex.Message));
                }
            }

            return Task.FromResult(mediaList);

        }
    }
}