using System.Net.Http;
using ClaudeDo.Releases;
using ClaudeDo.Ui.Services;

namespace ClaudeDo.Ui.Tests.Services;

public class UpdateCheckServiceTests
{
    private sealed class FakeReleaseClient : IReleaseClient
    {
        public GiteaRelease? Release { get; set; }
        public bool Throw { get; set; }
        public TaskCompletionSource<GiteaRelease?>? Gate { get; set; }

        public Task<GiteaRelease?> GetLatestReleaseAsync(CancellationToken ct)
        {
            if (Gate is not null) return Gate.Task;
            if (Throw) throw new HttpRequestException();
            return Task.FromResult(Release);
        }

        public Task DownloadAsync(string url, string destPath, IProgress<long> progress, CancellationToken ct)
            => throw new NotSupportedException();
    }

    [Fact]
    public async Task Check_NewerRelease_SetsUpdateAvailable()
    {
        var svc = new UpdateCheckService(new FakeReleaseClient
        {
            Release = new GiteaRelease("v0.3.0", "r", new[] { new ReleaseAsset("ClaudeDo-0.3.0-win-x64.zip", "u", 1) }),
        },
        currentVersion: "0.1.0");

        await svc.CheckNowAsync(CancellationToken.None);

        Assert.Equal(UpdateCheckStatus.UpdateAvailable, svc.LastCheckStatus);
        Assert.True(svc.IsUpdateAvailable);
        Assert.Equal("0.3.0", svc.LatestVersion);
    }

    [Fact]
    public async Task Check_SameRelease_SetsUpToDate()
    {
        var svc = new UpdateCheckService(new FakeReleaseClient
        {
            Release = new GiteaRelease("v0.1.0", "r", new[] { new ReleaseAsset("ClaudeDo-0.1.0-win-x64.zip", "u", 1) }),
        },
        currentVersion: "0.1.0");

        await svc.CheckNowAsync(CancellationToken.None);

        Assert.Equal(UpdateCheckStatus.UpToDate, svc.LastCheckStatus);
        Assert.False(svc.IsUpdateAvailable);
    }

    [Fact]
    public async Task Check_NetworkError_SetsCheckFailedButDoesNotThrow()
    {
        var svc = new UpdateCheckService(new FakeReleaseClient { Throw = true }, "0.1.0");
        await svc.CheckNowAsync(CancellationToken.None);
        Assert.Equal(UpdateCheckStatus.CheckFailed, svc.LastCheckStatus);
        Assert.False(svc.Op.IsRunning);
    }

    [Fact]
    public async Task CheckNowAsync_WhileRunning_OpIsRunningTrue_ThenResetAfterCompletion()
    {
        var releases = new FakeReleaseClient { Gate = new TaskCompletionSource<GiteaRelease?>() };
        var svc = new UpdateCheckService(releases, "0.1.0");

        var check = svc.CheckNowAsync(CancellationToken.None);

        Assert.True(svc.Op.IsRunning);

        releases.Gate.SetResult(new GiteaRelease("v0.1.0", "r", new[] { new ReleaseAsset("ClaudeDo-0.1.0-win-x64.zip", "u", 1) }));
        await check;

        Assert.False(svc.Op.IsRunning);
    }
}
