using Microsoft.Extensions.Logging;
using System.IO;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

namespace JSMR.Infrastructure.Http;

public abstract class ApiClient(IHttpService http, ILogger logger, JsonSerializerOptions? json = null)
{
    protected async Task<T> GetJsonAsync<T>(string url, CancellationToken cancellationToken = default)
    {
        string response = await http.GetStringAsync(url, cancellationToken);

        return JsonSerializer.Deserialize<T>(response, json)
            ?? throw new InvalidOperationException($"Failed to deserialize JSON to {typeof(T).Name} from {url}.");
    }

    //protected async Task<T> GetJsonAsync<T>(
    //    string url,
    //    Action<HttpRequestHeaders>? configureHeaders = null,
    //    CancellationToken ct = default
    //    )
    //{
    //    using var req = new HttpRequestMessage(HttpMethod.Get, url);
    //    configureHeaders?.Invoke(req.Headers);

    //    LogRequest(req);

    //    using var res = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);
    //    await EnsureSuccess(res).ConfigureAwait(false);

    //    var stream = await res.Content.ReadAsStreamAsync(ct).ConfigureAwait(false);

    //    var model = await JsonSerializer.DeserializeAsync<T>(stream, json, ct).ConfigureAwait(false)
    //        ?? throw new InvalidOperationException($"Failed to deserialize JSON to {typeof(T).Name} from {url}.");

    //    return model;
    //}

    //protected async Task<TResponse> PostJsonAsync<TRequest, TResponse>(
    //    string url,
    //    TRequest payload,
    //    Action<HttpRequestHeaders>? configureHeaders = null,
    //    CancellationToken ct = default)
    //{
    //    var content = new StringContent(JsonSerializer.Serialize(payload, json), Encoding.UTF8, "application/json");
    //    using var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = content };
    //    configureHeaders?.Invoke(req.Headers);

    //    LogRequest(req);

    //    using var res = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, ct).ConfigureAwait(false);
    //    await EnsureSuccess(res).ConfigureAwait(false);

    //    var stream = await res.Content.ReadAsStreamAsync(ct).ConfigureAwait(false);

    //    var model = await JsonSerializer.DeserializeAsync<TResponse>(stream, json, ct).ConfigureAwait(false)
    //        ?? throw new InvalidOperationException($"Failed to deserialize JSON to {typeof(TResponse).Name} from {url}.");

    //    return model;
    //}

    //protected virtual void LogRequest(HttpRequestMessage req)
    //    => logger.LogDebug("HTTP {Method} {Uri}", req.Method, req.RequestUri);

    //protected virtual void LogFailure(HttpResponseMessage res, string body)
    //    => logger.LogWarning("HTTP {Status} for {Uri}. Body: {Body}", (int)res.StatusCode, res.RequestMessage?.RequestUri, Truncate(body, 500));

    //protected static string Truncate(string s, int max) => s.Length <= max ? s : s[..max] + "…";

    //protected async Task EnsureSuccess(HttpResponseMessage res)
    //{
    //    if (res.IsSuccessStatusCode) return;

    //    string body;
    //    try { body = await res.Content.ReadAsStringAsync().ConfigureAwait(false); }
    //    catch { body = "<unable to read body>"; }

    //    LogFailure(res, body);

    //    Throw a richer exception(you can customize per API)
    //    throw new HttpRequestException(
    //        $"Request to {res.RequestMessage?.RequestUri} failed: {(int)res.StatusCode} {res.ReasonPhrase}. Body: {Truncate(body, 1000)}",
    //        null,
    //        res.StatusCode);
    //}
}