using Microsoft.VisualStudio.TestTools.UnitTesting;
using YMhut.Box.Core.Tools;

namespace YMhut.Box.Tests;

[TestClass]
public sealed class ToolWorkerTests
{
    [TestMethod]
    public void WorkerProtocolRoundTripsExecuteMessage()
    {
        var message = new ToolWorkerMessage(
            ToolWorkerProtocol.ExecuteTool,
            "req-1",
            ToolId: "json_formatter",
            Input: "{\"name\":\"YMhut\"}",
            TimeoutMs: 120000,
            Language: "en-US");

        var line = ToolWorkerProtocol.Serialize(message);
        var parsed = ToolWorkerProtocol.Deserialize(line);

        Assert.IsNotNull(parsed);
        Assert.AreEqual(ToolWorkerProtocol.ExecuteTool, parsed.Type);
        Assert.AreEqual("req-1", parsed.RequestId);
        Assert.AreEqual("json_formatter", parsed.ToolId);
        Assert.AreEqual("{\"name\":\"YMhut\"}", parsed.Input);
        Assert.AreEqual(120000, parsed.TimeoutMs);
        Assert.AreEqual("en-US", parsed.Language);
    }

    [TestMethod]
    public async Task InProcessWorkerExecutesToolByModule()
    {
        var module = new ToolCatalog().GetById("json_formatter")!;
        var worker = new ToolWorkerService();

        var result = await worker.ExecuteToolAsync(module, "{\"name\":\"YMhut\"}");

        Assert.IsTrue(result.Ok);
        StringAssert.Contains(result.Output, "\"name\": \"YMhut\"");
    }

    [TestMethod]
    public async Task InProcessWorkerHonorsCancellation()
    {
        var worker = new ToolWorkerService();
        using var source = new CancellationTokenSource();
        await source.CancelAsync();

        try
        {
            await worker.RunAsync(
                async token =>
                {
                    await Task.Delay(TimeSpan.FromSeconds(5), token);
                    return true;
                },
                source.Token);
        }
        catch (TaskCanceledException)
        {
            return;
        }

        Assert.Fail("Expected TaskCanceledException.");
    }
}
