using System;
using System.Threading.Tasks;

using AIRuntime.Runtime.Capabilities;
using AIRuntime.Runtime.Tools;
using AIRuntime.Runtime.Core;

using NUnit.Framework;


namespace AIRuntime.Tests
{
    public sealed class CapabilityInfrastructureTests
    {
        [Test]
        public void TimingMiddlewareRecordsSuccessfulCompletion()
        {
            CapabilityContext context =
                new CapabilityContext();

            TimingMiddleware middleware =
                new TimingMiddleware();


            middleware.InvokeAsync(
                    context,
                    ignored => Task.CompletedTask)
                .GetAwaiter()
                .GetResult();


            Assert.AreNotEqual(
                default(DateTime),
                context.FinishedUtc);

            Assert.GreaterOrEqual(
                context.Duration,
                TimeSpan.Zero);
        }


        [Test]
        public void TimingMiddlewareRecordsFailedCompletion()
        {
            CapabilityContext context =
                new CapabilityContext();

            TimingMiddleware middleware =
                new TimingMiddleware();


            Assert.Throws<InvalidOperationException>(
                () => middleware.InvokeAsync(
                        context,
                        ignored => Task.FromException(
                            new InvalidOperationException(
                                "Expected failure.")))
                    .GetAwaiter()
                    .GetResult());


            Assert.AreNotEqual(
                default(DateTime),
                context.FinishedUtc);

            Assert.GreaterOrEqual(
                context.Duration,
                TimeSpan.Zero);
        }


        [Test]
        public void ValidationResultAggregatesErrors()
        {
            ValidationResult result =
                new ValidationResult();


            Assert.IsTrue(
                result.IsValid);


            result.Add(
                "First error.");

            result.Add(
                "Second error.");


            Assert.IsFalse(
                result.IsValid);

            Assert.AreEqual(
                2,
                result.Errors.Count);

            Assert.AreEqual(
                "First error." +
                Environment.NewLine +
                "Second error.",
                result.ToString());
        }


        [Test]
        public void ToolExecutorRequiresDispatcher()
        {
            Assert.Throws<ArgumentNullException>(
                () => new ToolExecutor(
                    null));
        }


        [Test]
        public void Conversation_ExtractsDurableCapabilityArtifacts()
        {
            Conversation conversation = new Conversation();
            conversation.AddCapabilityResult(
                "call-1",
                "capture_game_view",
                "{\"Succeeded\":true,\"Artifacts\":[{\"Kind\":\"Image\",\"Path\":\"Outputs/frame.png\",\"MediaType\":\"image/png\",\"Sha256\":\"abc\",\"Bytes\":42}]}");

            Assert.AreEqual(1, conversation.Messages.Count);
            Assert.AreEqual(1, conversation.Messages[0].Attachments.Count);
            Assert.AreEqual("Outputs/frame.png", conversation.Messages[0].Attachments[0].Path);
            Assert.AreEqual("image/png", conversation.Messages[0].Attachments[0].MediaType);
            Assert.AreEqual(42, conversation.Messages[0].Attachments[0].Bytes);
        }
    }
}
