using System;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;

namespace NzbDrone.Core.Notifications.Ntfy
{
    public interface INtfyProxy
    {
        void SendNotification(string title, string message, NtfySettings settings);

        ValidationFailure Test(NtfySettings settings);
    }

    public class NtfyProxy : INtfyProxy
    {
        private const string DEFAULT_PUSH_URL = "https://ntfy.sh";

        private readonly IHttpClient _httpClient;

        private readonly Logger _logger;

        public NtfyProxy(IHttpClient httpClient, Logger logger)
        {
            _httpClient = httpClient;
            _logger = logger;
        }

        public void SendNotification(string title, string message, NtfySettings settings)
        {
            var error = false;

            var serverUrl = settings.ServerUrl.IsNullOrWhiteSpace() ? DEFAULT_PUSH_URL : settings.ServerUrl;

            foreach (var topic in settings.Topics)
            {
                var request = BuildTopicRequest(serverUrl, topic);

                try
                {
                    SendNotification(title, message, request, settings);
                }
                catch (NtfyException ex)
                {
                    _logger.Error(ex, "Unable to send test message to {0}", topic);
                    error = true;
                }
            }

            if (error)
            {
                throw new NtfyException("Unable to send Ntfy notifications to all topics");
            }
        }

        private HttpRequestBuilder BuildTopicRequest(string serverUrl, string topic)
        {
            var trimServerUrl = serverUrl.TrimEnd('/');

            var requestBuilder = new HttpRequestBuilder($"{trimServerUrl}/{topic}").Post();

            return requestBuilder;
        }

        public ValidationFailure Test(NtfySettings settings)
        {
            try
            {
                const string title = "Readarr - Test Notification";

                const string body = "This is a test message from Readarr";

                SendNotification(title, body, settings);
            }
            catch (HttpException ex)
            {
                if (ex.Response.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
                {
                    if (!settings.AccessToken.IsNullOrWhiteSpace())
                    {
                        _logger.Error(ex, "Invalid token");
                        return new ValidationFailure("AccessToken", "Invalid token");
                    }

                    if (!settings.UserName.IsNullOrWhiteSpace() && !settings.Password.IsNullOrWhiteSpace())
                    {
                        _logger.Error(ex, "Invalid username or password");
                        return new ValidationFailure("UserName", "Invalid username or password");
                    }

                    _logger.Error(ex, "Authorization is required");
                    return new ValidationFailure("AccessToken", "Authorization is required");
                }

                _logger.Error(ex, "Unable to send test message");
                return new ValidationFailure("ServerUrl", "Unable to send test message");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Unable to send test message");
                return new ValidationFailure("", "Unable to send test message");
            }

            return null;
        }

        private void SendNotification(string title, string message, HttpRequestBuilder requestBuilder, NtfySettings settings)
        {
            try
            {
                requestBuilder.AddQueryParam("title", title);
                requestBuilder.AddQueryParam("message", message);
                requestBuilder.AddQueryParam("priority", settings.Priority.ToString());

                if (settings.Tags.Any())
                {
                    requestBuilder.AddQueryParam("tags", settings.Tags.Join(","));
                }

                if (!settings.ClickUrl.IsNullOrWhiteSpace())
                {
                    requestBuilder.AddQueryParam("click", settings.ClickUrl);
                }

                if (!settings.AccessToken.IsNullOrWhiteSpace())
                {
                    requestBuilder.Headers.Set("Authorization", $"Bearer {settings.AccessToken}");
                }
                else if (!settings.UserName.IsNullOrWhiteSpace() && !settings.Password.IsNullOrWhiteSpace())
                {
                    requestBuilder.NetworkCredential = new BasicNetworkCredential(settings.UserName, settings.Password);
                }

                var request = requestBuilder.Build();

                _httpClient.Execute(request);
            }
            catch (HttpException ex)
            {
                if (ex.Response.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
                {
                    _logger.Error(ex, "Authorization is required");
                    throw;
                }

                throw new NtfyException("Unable to send text message: {0}", ex, ex.Message);
            }
        }
    }
}
