using System.Net;
using System.Net.Http.Headers;

namespace Kbx.Shared.Providers;

public sealed class KrxOpenApiAdapter(HttpClient http, IKbxProviderSecretStore secrets) : IKbxExternalProviderAdapter
{
    public string ProviderId => "provider.krx.openapi";

    public async Task<KbxProviderResult<string>> InvokeApprovedServiceAsync(KrxApprovedServiceRequest request, CancellationToken ct)
    {
        if (!request.ServiceUri.IsAbsoluteUri || request.ServiceUri.Scheme != Uri.UriSchemeHttps || !request.ServiceUri.Host.EndsWith(".krx.co.kr", StringComparison.OrdinalIgnoreCase))
            return new(KbxProviderResultKind.PermanentFailure, Code:"KRX_SERVICE_URL_NOT_APPROVED", Message:"KRX 승인 서비스의 HTTPS URL만 사용할 수 있습니다.");
        if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Post)
            return new(KbxProviderResultKind.PermanentFailure, Code:"KRX_METHOD_NOT_ALLOWED", Message:"조회성 GET/POST만 허용됩니다.");

        var key = await secrets.GetRequiredAsync("ExternalProviders:Krx:AuthKey", ct);
        var uri = AppendQuery(request.ServiceUri, request.Query);
        using var message = new HttpRequestMessage(request.Method, uri);
        message.Headers.TryAddWithoutValidation("AUTH_KEY", key);
        if (request.Method == HttpMethod.Post && request.Body is not null)
            message.Content = new StringContent(request.Body, System.Text.Encoding.UTF8, "application/json");
        using var response = await http.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, ct);
        var body = await response.Content.ReadAsStringAsync(ct);
        if (response.IsSuccessStatusCode) return new(KbxProviderResultKind.Success, body, HttpStatus:(int)response.StatusCode);
        var transient = response.StatusCode is HttpStatusCode.RequestTimeout or (HttpStatusCode)429 || (int)response.StatusCode >= 500;
        return new(transient ? KbxProviderResultKind.TransientFailure : KbxProviderResultKind.PermanentFailure, Code:$"HTTP_{(int)response.StatusCode}", Message:"KRX OPEN API 호출이 실패했습니다.", HttpStatus:(int)response.StatusCode);
    }

    private static Uri AppendQuery(Uri uri, IReadOnlyDictionary<string,string?> query)
    {
        if (query.Count == 0) return uri;
        var parts = query.Where(x => x.Value is not null).Select(x => $"{Uri.EscapeDataString(x.Key)}={Uri.EscapeDataString(x.Value!)}");
        var builder = new UriBuilder(uri) { Query = string.Join("&", parts) };
        return builder.Uri;
    }
}
