using Microsoft.AspNetCore.SignalR;
using Moq;
using server.Hubs;
using server.Services;

public class ProgressTrackerTest
{
    [Fact]
    public async Task Test_ProgressReporter_Basic()
    {
        int reportedValue = -1;
        var reporter = new ProgressReporter(async v => { reportedValue = v; await Task.CompletedTask; }, 0, 100, 10);

        // Report
        reporter.Report(50);
        Assert.Equal(50, reporter.Progress);
        Assert.Equal(ProgressStatus.InProgress, reporter.Status);
        Assert.Equal(50, reportedValue);

        // Increase by step
        reporter.Increase();
        Assert.Equal(60, reporter.Progress);

        // Increase by value
        reporter.Increase(20);
        Assert.Equal(80, reporter.Progress);

        // Finish
        reporter.Finish();
        Assert.Equal(ProgressStatus.Completed, reporter.Status);
        Assert.Equal(100, reporter.Progress);

        // Cancel
        reporter = new ProgressReporter(async v => { reportedValue = v; await Task.CompletedTask; }, 0, 100, 10);
        reporter.Cancel();
        Assert.Equal(ProgressStatus.Canceled, reporter.Status);
        Assert.Equal("User Cancelled", reporter.ErrorMessage);

        // Error
        reporter = new ProgressReporter(async v => { reportedValue = v; await Task.CompletedTask; }, 0, 100, 10);
        reporter.Error("Test Error");
        Assert.Equal(ProgressStatus.Failed, reporter.Status);
        Assert.Equal("Test Error", reporter.ErrorMessage);

        // CreateChild
        var parent = new ProgressReporter(async v => { await Task.CompletedTask; }, 10, 100, 5);
        var child = parent.CreateChild(50, 5);
        Assert.Equal(ProgressStatus.Pending, child.Status);
        Assert.NotNull(child);

        // Child Increase
        child.Increase();
        Assert.Equal(ProgressStatus.InProgress, child.Status);
        Assert.Equal(20, child.ProgressPercent);
        Assert.Equal(20, parent.Progress);

        // Child Complete
        child.Finish();
        Assert.Equal(ProgressStatus.Completed, child.Status);
        Assert.Equal(100, child.ProgressPercent);
        Assert.Equal(60, parent.Progress);
    }

    [Fact]
    public void Test_ProgressTrackerService_Basic()
    {
        // Mock SignalR HubContext
        var mockHubContext = new Mock<IHubContext<ProgressHub, IProgressReceiver>>();
        var service = new ProgressTrackerService(mockHubContext.Object);

        // CreateTask
        var (taskId, reporter) = service.CreateTask();
        Assert.NotNull(taskId);
        Assert.NotNull(reporter);

        // GetReporter
        var optReporter = service.GetReporter(taskId);
        Assert.True(optReporter.HasValue);
        Assert.Equal(reporter, optReporter.Value);

        // GetProgressStatus
        var optStatus = service.GetProgressStatus(taskId);
        Assert.True(optStatus.HasValue);
        Assert.Equal(ProgressStatus.Pending, optStatus.Value);

        // BindTask
        var bindResult = service.BindTask(taskId, "conn1");
        Assert.True(bindResult);

        // CancelTask
        var cancelResult = service.CancelTask(taskId);
        Assert.True(cancelResult);

        // After cancel, status should be Cancelled
        var optStatus2 = service.GetProgressStatus(taskId);
        Assert.True(optStatus2.HasValue);
        Assert.Equal(ProgressStatus.Canceled, optStatus2.Value);
    }
}
