using HermesSocketLibrary.Socket.Data;
using HermesSocketServer.Services;

namespace HermesSocketServer.Requests
{
    public class RequestManager : IRequestManager
    {
        private readonly IDictionary<string, IRequest> _requests;
        private readonly ChannelManager _channels;
        private readonly Serilog.ILogger _logger;


        public RequestManager(IEnumerable<IRequest> requests, ChannelManager channels, Serilog.ILogger logger)
        {
            _requests = requests.ToDictionary(r => r.Name, r => r);
            _channels = channels;
            _logger = logger;
        }

        public async Task<RequestResult> Grant(string sender, RequestMessage? message)
        {
            if (message == null || message.Type == null)
            {
                _logger.Debug($"Request type does not exist [id: {message.RequestId}][nounce: {message.Nounce}]");
                return RequestResult.Failed("Request type does not exist.");
            }

            var channel = _channels.Get(sender);
            if (channel == null)
            {
                _logger.Debug($"Channel does not exist [id: {message.RequestId}][nounce: {message.Nounce}]");
                return RequestResult.Failed("Channel does not exist.");
            }

            if (!_requests.TryGetValue(message.Type, out IRequest? request) || request == null)
            {
                _logger.Warning($"Could not find request [type: {message.Type}]");
                return RequestResult.Failed("Request does not exist.");
            }

            if (request.RequiredKeys.Any())
            {
                if (message.Data == null)
                {
                    _logger.Debug($"Request is lacking data entries [id: {message.RequestId}][nounce: {message.Nounce}]");
                    return RequestResult.Failed($"Request is lacking data entries.");
                }

                foreach (var key in request.RequiredKeys)
                {
                    if (!message.Data.ContainsKey(key))
                    {
                        _logger.Debug($"Request is missing '{key}' in its data entries [id: {message.RequestId}][nounce: {message.Nounce}]");
                        return RequestResult.Failed($"Request is missing '{key}' in its data entries.");
                    }
                }
            }

            try
            {
                return await request.Grant(sender, message.Data);
            }
            catch (Exception e)
            {
                _logger.Error(e, $"Failed to grant a request during processing [type: {message.Type}]");
                return RequestResult.Failed("Failed to grant request during processing: " + e.Message);
            }
        }
    }
}