using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using AIRuntime.Runtime.Models;
using AIRuntime.Runtime.Providers.Models;
using AIRuntime.Runtime.Providers.Ollama;

using NUnit.Framework;


namespace AIRuntime.Tests
{
    public sealed class OllamaProviderTests
    {
        [Test]
        public void ConstructorRequiresClient()
        {
            Assert.Throws<ArgumentNullException>(
                () => new OllamaProvider(
                    (IOllamaClient)null));
        }


        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[null]}}]}")]
        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[{\"id\":\"call-1\"}]}}]}")]
        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[{\"id\":\"\",\"function\":{\"name\":\"read_file\",\"arguments\":\"{}\"}}]}}]}")]
        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[{\"id\":\"call-1\",\"function\":{\"name\":\"\",\"arguments\":\"{}\"}}]}}]}")]
        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[{\"id\":\"call-1\",\"function\":{\"name\":\"read_file\",\"arguments\":\"\"}}]}}]}")]
        [TestCase(
            "{\"choices\":[{\"message\":{\"tool_calls\":[{\"id\":\"call-1\",\"function\":{\"name\":\"read_file\",\"arguments\":\"not-json\"}}]}}]}")]
        public void ProviderRejectsMalformedToolCall(
            string responseJson)
        {
            OllamaProvider provider =
                new OllamaProvider(
                    new FakeOllamaClient(
                        responseJson));


            InvalidOperationException exception =
                Assert.Throws<InvalidOperationException>(
                    () => provider.ChatAsync(
                            new List<ConversationMessage>(),
                            new List<ProviderTool>())
                        .GetAwaiter()
                        .GetResult());


            StringAssert.Contains(
                "invalid response",
                exception.Message);
        }


        [Test]
        public void ProviderMapsValidToolCall()
        {
            const string responseJson =
                "{\"choices\":[{\"message\":{\"content\":\"\"," +
                "\"tool_calls\":[{\"id\":\"call-1\",\"function\":{" +
                "\"name\":\"read_file\",\"arguments\":\"{\\\"path\\\":\\\"README.md\\\"}\"}}]}}]}";

            OllamaProvider provider =
                new OllamaProvider(
                    new FakeOllamaClient(
                        responseJson));


            ChatCompletion completion =
                provider.ChatAsync(
                        new List<ConversationMessage>(),
                        new List<ProviderTool>())
                    .GetAwaiter()
                    .GetResult();


            Assert.IsTrue(
                completion.HasToolCalls);

            Assert.AreEqual(
                "call-1",
                completion.ToolCalls[0].Id);

            Assert.AreEqual(
                "read_file",
                completion.ToolCalls[0].Name);
        }


        private sealed class FakeOllamaClient :
            IOllamaClient
        {
            private readonly string _responseJson;


            public string Model =>
                "test-model";


            public FakeOllamaClient(
                string responseJson)
            {
                _responseJson =
                    responseJson;
            }


            public Task<string> ChatAsync(
                string jsonBody,
                CancellationToken cancellationToken)
            {
                cancellationToken
                    .ThrowIfCancellationRequested();

                return Task.FromResult(
                    _responseJson);
            }
        }
    }
}
