using System.IO;
using System.Net.Http;
using System.Text.Json;

namespace ClaudeDo.Releases;

public sealed class ReleaseClient : IReleaseClient
{
    public const string DefaultApiBase = "https://git.kuns.dev/api/v1/repos/releases/ClaudeDo";

    private readonly HttpClient _http;
    private readonly string _apiBase;

    public ReleaseClient(HttpClient http, string apiBase = DefaultApiBase)
    {
        _http = http;
        _apiBase = apiBase.TrimEnd('/');
    }

    public async Task<GiteaRelease?> GetLatestReleaseAsync(CancellationToken ct)
    {
        try
        {
            using var response = await _http.GetAsync($"{_apiBase}/releases/latest", ct);
            if (!response.IsSuccessStatusCode) return null;
            var json = await response.Content.ReadAsStringAsync(ct);
            return ParseRelease(json);
        }
        catch (HttpRequestException) { return null; }
        catch (TaskCanceledException) when (!ct.IsCancellationRequested) { return null; }
    }

    public async Task DownloadAsync(string url, string destPath, IProgress<long> progress, CancellationToken ct)
    {
        using var response = await _http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, ct);
        response.EnsureSuccessStatusCode();

        await using var input = await response.Content.ReadAsStreamAsync(ct);
        await using var output = File.Create(destPath);

        var buffer = new byte[81920];
        long total = 0;
        int read;
        while ((read = await input.ReadAsync(buffer, ct)) > 0)
        {
            await output.WriteAsync(buffer.AsMemory(0, read), ct);
            total += read;
            progress.Report(total);
        }
    }

    private static GiteaRelease? ParseRelease(string json)
    {
        try
        {
            using var doc = JsonDocument.Parse(json);
            var root = doc.RootElement;
            if (!root.TryGetProperty("tag_name", out var tagEl)) return null;

            var tag = tagEl.GetString() ?? "";
            var name = root.TryGetProperty("name", out var nameEl) ? (nameEl.GetString() ?? "") : "";

            var assets = new List<ReleaseAsset>();
            if (root.TryGetProperty("assets", out var arr) && arr.ValueKind == JsonValueKind.Array)
            {
                foreach (var item in arr.EnumerateArray())
                {
                    if (!item.TryGetProperty("name", out var nameField)) continue;
                    if (!item.TryGetProperty("browser_download_url", out var urlField)) continue;

                    var aName = nameField.GetString() ?? "";
                    var aUrl = urlField.GetString() ?? "";
                    var aSize = item.TryGetProperty("size", out var s) ? s.GetInt64() : 0L;
                    assets.Add(new ReleaseAsset(aName, aUrl, aSize));
                }
            }

            return new GiteaRelease(tag, name, assets);
        }
        catch (JsonException)
        {
            return null;
        }
    }
}
