using Knot.Shared.Kernel;
using Knot.Contracts.Settings.Application.Abstractions;
using Knot.Contracts.Settings.Application.DTOs;
using Knot.Shared.Kernel.Constants;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediatR;

namespace Knot.Modules.Klipy.Application.Klipy.Queries;

public record SearchGifsQuery(string Query, int Page = 1) : IQuery<JsonElement?>;

internal sealed class SearchGifsQueryHandler : IQueryHandler<SearchGifsQuery, JsonElement?>
{
    private readonly IKlipySettings _settings;
    private readonly IMemoryCache _cache;
    private readonly IHttpClientFactory _httpClientFactory;

    public SearchGifsQueryHandler(IKlipySettings settings, IMemoryCache cache, IHttpClientFactory httpClientFactory)
    {
        _settings = settings;
        _cache = cache;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<Result<JsonElement?>> Handle(SearchGifsQuery request, CancellationToken cancellationToken)
    {
        var conf = _settings.Current;
        if (!conf.Enabled || string.IsNullOrEmpty(conf.ApiKey))
            return Result.Failure<JsonElement?>(new Error(Errors.KlipyNotConfigured, "Klipy is not configured"));

        if (string.IsNullOrWhiteSpace(request.Query))
            return Result.Failure<JsonElement?>(new Error(Errors.InvalidQuery, "Invalid query parameter"));

        var cacheKey = $"klipy_search_{conf.ApiKey}_{request.Query.ToLowerInvariant()}_{request.Page}";
        if (_cache.TryGetValue(cacheKey, out JsonElement cachedResult))
            return Result.Success<JsonElement?>(cachedResult);

        var customerId = Knot.Shared.Kernel.Constants.Klipy.DefaultCustomerId;
        var client = _httpClientFactory.CreateClient();
        
        var queryParam = $"q={Uri.EscapeDataString(request.Query)}";
        var urlCo = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCo, conf.ApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceSearch, request.Page, 30, queryParam, customerId);

        var response = await client.GetAsync(urlCo, cancellationToken);
        if (!response.IsSuccessStatusCode)
        {
            if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                var urlCom = string.Format(Knot.Shared.Kernel.Constants.Klipy.ApiUrlCom, conf.ApiKey, Knot.Shared.Kernel.Constants.Klipy.ResourceSearch, request.Page, 30, queryParam, customerId);
                response = await client.GetAsync(urlCom, cancellationToken);
            }

            if (!response.IsSuccessStatusCode)
                return Result.Failure<JsonElement?>(new Error(Errors.KlipySearchError, "Klipy Search API Error"));
        }

        var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: cancellationToken);
        _cache.Set(cacheKey, result, TimeSpan.FromMinutes(Knot.Shared.Kernel.Constants.Klipy.SearchCacheMinutes));
        
        return Result.Success<JsonElement?>(result);
    }
}

