using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YMhut.Box.Core.Tools;

namespace YMhut.Box.Tests;

[TestClass]
public sealed class ToolWebPayloadSerializationTests
{
    private static readonly JsonSerializerOptions Options = CreateOptions();

    [TestMethod]
    public void ToolPagePayloadSerializesRulesParametersAndActions()
    {
        var catalog = new ToolCatalog();
        var module = catalog.GetById("json_formatter")!;
        var spec = ToolPageSpecCatalog.For(module);
        var experiences = new ToolResultExperienceCatalog(catalog);

        Assert.IsNotEmpty(spec.Rules);

        var payload = new ToolPageWebPayload(
            module.Id,
            module.Metadata.Name,
            module.Metadata.Description,
            spec,
            experiences.GetRequiredPage(module.Id),
            new ToolInputState(
                """{"name":"YMhut"}""",
                [new ToolInputField("input", "Input", "textarea", """{"name":"YMhut"}""")],
                new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["mode"] = "format" },
                new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["hint"] = "Enter values or choose options, then run the tool." }),
            "Light",
            "zh-CN",
            new ToolResultPrivacyPolicy(["update.ymhut.cn"]),
            new ToolPageRuntimeMetadata(DateTimeOffset.UnixEpoch, AutoRun: false, OfflineCapable: true, "Dev", "\uE943"),
            ["run", "copyResult", "showRaw"]);

        var json = JsonSerializer.Serialize(payload, Options);
        var roundTrip = JsonSerializer.Deserialize<ToolPageWebPayload>(json, Options);

        Assert.IsNotNull(roundTrip);
        Assert.AreEqual(module.Id, roundTrip.ToolId);
        Assert.IsNotEmpty(roundTrip.Spec.Rules);
        Assert.IsNotEmpty(roundTrip.Spec.Parameters);
        Assert.AreEqual("format", roundTrip.Input.Rules["mode"]);
        CollectionAssert.Contains(roundTrip.AvailableActions.ToList(), "copyResult");
    }

    [TestMethod]
    public void ToolResultPayloadSerializesRepresentativeBlockKinds()
    {
        var catalog = new ToolCatalog();
        var module = catalog.GetById("hotboard")!;
        var experiences = new ToolResultExperienceCatalog(catalog);
        var blocks = new[]
        {
            ToolResultBlock.KeyValue("Details", [new("Key", "Value")]),
            ToolResultBlock.Table("Table", [new[] { "Name", "Value" }, new[] { "YMhut", "Box" }]),
            ToolResultBlock.List(ToolResultBlockKind.RankedList, "Ranking", [new("1", "First", "Trend", "ok", "https://example.com")]),
            ToolResultBlock.List(ToolResultBlockKind.NewsList, "News", [new("1", "Headline", "Source", "info", "https://example.com/news")]),
            ToolResultBlock.File("File", "report.txt", @"C:\Temp\report.txt"),
            ToolResultBlock.Link("Link", "YMhut", "https://example.com"),
            ToolResultBlock.Media(ToolResultBlockKind.Media, "Media", "video", "https://example.com/video.mp4"),
            ToolResultBlock.Json("JSON", """{"ok":true}"""),
            ToolResultBlock.List(ToolResultBlockKind.Status, "Status", [new("OK", "Ready", "", "ok", "")])
        };
        var document = new ToolResultDocument(
            module.Id,
            ToolResultKind.RankedList,
            "raw output",
            blocks,
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { ["displayProfile"] = "cards" },
            "raw output",
            "test",
            "ok");
        var payload = new ToolResultWebPayload(
            module.Id,
            module.Metadata.Name,
            document,
            experiences.GetRequired(module.Id).ExperienceId,
            "Dark",
            "en-US",
            new ToolResultPrivacyPolicy(["update.ymhut.cn"]),
            new ToolResultRuntimeMetadata(42, DateTimeOffset.UnixEpoch, Cached: false, "test", new Dictionary<string, string>()),
            experiences.GetRequired(module.Id));

        var json = JsonSerializer.Serialize(payload, Options);
        var roundTrip = JsonSerializer.Deserialize<ToolResultWebPayload>(json, Options);

        Assert.IsNotNull(roundTrip);
        Assert.HasCount(blocks.Length, roundTrip.ResultDocument.Blocks);
        CollectionAssert.Contains(roundTrip.ResultDocument.Blocks.Select(block => block.Kind).ToList(), ToolResultBlockKind.RankedList);
        CollectionAssert.Contains(roundTrip.ResultDocument.Blocks.Select(block => block.Kind).ToList(), ToolResultBlockKind.Media);
        StringAssert.Contains(json, nameof(ToolResultBlockKind.RankedList));
    }

    private static JsonSerializerOptions CreateOptions()
    {
        var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
        options.Converters.Add(new JsonStringEnumConverter());
        return options;
    }
}
