using System.Text.Json;

namespace Kbx.Shared.Providers;

public sealed class OpenDartAdapter(HttpClient http, IKbxProviderSecretStore secrets) : IKbxExternalProviderAdapter
{
    private static readonly Uri BaseUri = new("https://opendart.fss.or.kr/api/");
    public string ProviderId => "provider.opendart";

    public Task<KbxProviderResult<JsonDocument>> GetDisclosuresAsync(IReadOnlyDictionary<string,string?> query, CancellationToken ct)
        => GetJsonAsync("list.json", query, ct);
    public Task<KbxProviderResult<JsonDocument>> GetCompanyAsync(string corpCode, CancellationToken ct)
        => GetJsonAsync("company.json", new Dictionary<string,string?> { ["corp_code"] = corpCode }, ct);

    public async Task<KbxProviderResult<byte[]>> DownloadCorpCodeAsync(CancellationToken ct)
    {
        var key = await secrets.GetRequiredAsync("ExternalProviders:OpenDart:ApiKey", ct);
        var uri = new Uri(BaseUri, $"corpCode.xml?crtfc_key={Uri.EscapeDataString(key)}");
        using var response = await http.GetAsync(uri, ct);
        var bytes = await response.Content.ReadAsByteArrayAsync(ct);
        if (response.IsSuccessStatusCode) return new(KbxProviderResultKind.Success, bytes, HttpStatus:(int)response.StatusCode);
        return new((int)response.StatusCode >= 500 ? KbxProviderResultKind.TransientFailure : KbxProviderResultKind.PermanentFailure, Code:$"HTTP_{(int)response.StatusCode}", Message:"OPENDART 고유번호 파일 호출 실패", HttpStatus:(int)response.StatusCode);
    }

    private async Task<KbxProviderResult<JsonDocument>> GetJsonAsync(string path, IReadOnlyDictionary<string,string?> query, CancellationToken ct)
    {
        var key = await secrets.GetRequiredAsync("ExternalProviders:OpenDart:ApiKey", ct);
        var pairs = new List<string> { $"crtfc_key={Uri.EscapeDataString(key)}" };
        pairs.AddRange(query.Where(x=>x.Value is not null).Select(x=>$"{Uri.EscapeDataString(x.Key)}={Uri.EscapeDataString(x.Value!)}"));
        var uri = new Uri(BaseUri, path + "?" + string.Join("&", pairs));
        using var response = await http.GetAsync(uri, ct);
        var text = await response.Content.ReadAsStringAsync(ct);
        if (!response.IsSuccessStatusCode)
            return new((int)response.StatusCode >= 500 || (int)response.StatusCode == 429 ? KbxProviderResultKind.TransientFailure : KbxProviderResultKind.PermanentFailure, Code:$"HTTP_{(int)response.StatusCode}", Message:"OPENDART HTTP 호출 실패", HttpStatus:(int)response.StatusCode);
        JsonDocument doc;
        try { doc = JsonDocument.Parse(text); } catch { return new(KbxProviderResultKind.PermanentFailure, Code:"DART_INVALID_JSON", Message:"OPENDART 응답 JSON을 해석할 수 없습니다."); }
        var root = doc.RootElement;
        var status = root.TryGetProperty("status", out var s) ? s.GetString() : null;
        var message = root.TryGetProperty("message", out var m) ? m.GetString() : null;
        return status switch
        {
            "000" or null => new(KbxProviderResultKind.Success, doc),
            "013" => new(KbxProviderResultKind.NoData, doc, status, message),
            "020" or "800" or "900" => new(KbxProviderResultKind.TransientFailure, doc, status, message),
            _ => new(KbxProviderResultKind.PermanentFailure, doc, status, message)
        };
    }
}
