using System;
using System.IO;
using System.Threading.Tasks;

using AIRuntime.Runtime;
using AIRuntime.Runtime.Capabilities;
using AIRuntime.Runtime.Capabilities.Permissions;
using AIRuntime.Runtime.Filesystem;

using NUnit.Framework;

using UnityEngine;


namespace AIRuntime.Tests.EditMode
{
    public sealed class AIRuntimeBuilderTests
    {
        private sealed class CountingMiddleware :
            ICapabilityMiddleware
        {
            public int InvocationCount { get; private set; }


            public async Task InvokeAsync(
                CapabilityContext context,
                CapabilityDelegate next)
            {
                InvocationCount++;

                await next(context);
            }
        }


        private sealed class TestModule :
            IAIRuntimeModule
        {
            private readonly CountingMiddleware _middleware;


            public TestModule(
                CountingMiddleware middleware)
            {
                _middleware = middleware;
            }


            public void Configure(
                AIRuntimeBuilder builder)
            {
                builder
                    .WithoutConsoleObserver()
                    .UseMiddleware(_middleware)
                    .RegisterCapability(
                        new FileExistsCapability())
                    .ConfigureRuntime(
                        runtime =>
                            runtime.AllowPermission(
                                CapabilityPermission.ReadOnly));
            }
        }


        [Test]
        public void Module_ComposesMiddlewareAndRuntimeConfiguration()
        {
            string projectRoot =
                Directory.GetParent(
                        Application.dataPath)
                    ?.FullName ??
                Application.dataPath;

            CountingMiddleware middleware =
                new CountingMiddleware();

            AIRuntime.Runtime.AIRuntime runtime =
                new AIRuntimeBuilder(
                        projectRoot)
                    .AddModule(
                        new TestModule(
                            middleware))
                    .Build();

            string result =
                runtime.ExecuteCapabilityAsync(
                        "file_exists",
                        "{\"path\":\"ProjectSettings/ProjectVersion.txt\"}")
                    .GetAwaiter()
                    .GetResult();

            Assert.AreEqual(
                1,
                middleware.InvocationCount);
            StringAssert.Contains(
                "true",
                result.ToLowerInvariant());
        }


        [Test]
        public void Builder_IsSingleUseAndImmutableAfterBuild()
        {
            string projectRoot =
                Directory.GetParent(
                        Application.dataPath)
                    ?.FullName ??
                Application.dataPath;

            AIRuntimeBuilder builder =
                new AIRuntimeBuilder(
                    projectRoot);

            Assert.IsNotNull(
                builder.Build());

            Assert.Throws<InvalidOperationException>(
                () => builder.Build());
            Assert.Throws<InvalidOperationException>(
                () => builder.WithoutConsoleObserver());
        }
    }
}
