using System.Threading;
using MCPForUnity.Editor.Services.AssetGen.Http;
using MCPForUnity.Editor.Services.AssetGen.Providers;
using NUnit.Framework;

namespace MCPForUnityTests.Editor.AssetGen
{
    public class FalAdapterTests
    {
        private const string Resp = "https://queue.fal.run/fal-ai/flux-2/requests/r1";

        private static HttpResult Json(string body) => new HttpResult { Status = 200, IsSuccess = true, Text = body };

        private static ImageGenRequest Req() => new ImageGenRequest { Provider = "fal", Mode = "text", Prompt = "a cat" };

        [Test]
        public void Submit_PostsModelEndpoint_WithKeyHeader_ReturnsResponseUrl()
        {
            var fake = new FakeHttpTransport
            {
                Handler = spec => Json("{\"request_id\":\"r1\",\"response_url\":\"" + Resp + "\"}")
            };
            var adapter = new FalAdapter();

            string pid = adapter.SubmitAsync(Req(), "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            Assert.AreEqual(Resp, pid);
            HttpRequestSpec sent = fake.RecordedRequests[0];
            Assert.AreEqual("POST", sent.Method);
            StringAssert.Contains("fal-ai/flux-2", sent.Url);
            Assert.IsTrue(sent.Headers.ContainsKey("Authorization"));
            StringAssert.StartsWith("Key ", sent.Headers["Authorization"]);
        }

        [Test]
        public void Submit_WithDimensions_IncludesImageSize()
        {
            var fake = new FakeHttpTransport
            {
                Handler = spec => Json("{\"request_id\":\"r1\",\"response_url\":\"" + Resp + "\"}")
            };
            var adapter = new FalAdapter();
            var req = new ImageGenRequest { Provider = "fal", Mode = "text", Prompt = "a cat", Width = 512, Height = 768 };

            adapter.SubmitAsync(req, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            string sent = System.Text.Encoding.UTF8.GetString(fake.RecordedRequests[0].Body);
            StringAssert.Contains("image_size", sent);
            StringAssert.Contains("512", sent);
            StringAssert.Contains("768", sent);
        }

        [Test]
        public void Submit_ImageMode_UsesEditEndpoint_WithImageUrlsArray()
        {
            var fake = new FakeHttpTransport { Handler = _ => Json("{\"response_url\":\"" + Resp + "\"}") };
            var adapter = new FalAdapter();
            var req = new ImageGenRequest { Provider = "fal", Mode = "image", Prompt = "make it night", ImageUrl = "https://ex.com/in.png" };

            adapter.SubmitAsync(req, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            HttpRequestSpec rec = fake.RecordedRequests[0];
            StringAssert.Contains("/edit", rec.Url);
            string body = System.Text.Encoding.UTF8.GetString(rec.Body);
            StringAssert.Contains("image_urls", body);
            StringAssert.Contains("https://ex.com/in.png", body);
        }

        [Test]
        public void Poll_Completed_FetchesResult_ReturnsImageUrl()
        {
            var fake = new FakeHttpTransport
            {
                Handler = spec =>
                {
                    if (spec.Url.EndsWith("/status")) return Json("{\"status\":\"COMPLETED\"}");
                    return Json("{\"images\":[{\"url\":\"https://cdn.example.com/img.png\"}]}");
                }
            };
            var adapter = new FalAdapter();

            ProviderPollResult pr = adapter.PollAsync(Resp, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            Assert.AreEqual(ProviderPollState.Succeeded, pr.State);
            Assert.AreEqual("https://cdn.example.com/img.png", pr.DownloadUrl);
        }

        [Test]
        public void Submit_ImageMode_OmitsImageSize_EvenWithDimensions()
        {
            var fake = new FakeHttpTransport { Handler = _ => Json("{\"response_url\":\"" + Resp + "\"}") };
            var adapter = new FalAdapter();
            var req = new ImageGenRequest { Provider = "fal", Mode = "image", Prompt = "edit", ImageUrl = "https://ex.com/in.png", Width = 512, Height = 512 };

            adapter.SubmitAsync(req, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            string body = System.Text.Encoding.UTF8.GetString(fake.RecordedRequests[0].Body);
            StringAssert.DoesNotContain("image_size", body); // /edit derives size from the source image
        }

        [Test]
        public void Submit_ImageMode_FallbackResponseUrl_UsesBaseModelPath()
        {
            var fake = new FakeHttpTransport { Handler = _ => Json("{\"request_id\":\"r1\"}") }; // no response_url
            var adapter = new FalAdapter();
            var req = new ImageGenRequest { Provider = "fal", Mode = "image", Prompt = "edit", ImageUrl = "https://ex.com/in.png" };

            string pid = adapter.SubmitAsync(req, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            StringAssert.Contains("/fal-ai/flux-2/requests/r1", pid);
            StringAssert.DoesNotContain("/edit/requests", pid);
        }

        [Test]
        public void Poll_InProgress_ReturnsRunning()
        {
            var fake = new FakeHttpTransport { Handler = spec => Json("{\"status\":\"IN_PROGRESS\"}") };
            var adapter = new FalAdapter();

            ProviderPollResult pr = adapter.PollAsync(Resp, "falkey123", fake, CancellationToken.None).GetAwaiter().GetResult();

            Assert.AreEqual(ProviderPollState.Running, pr.State);
        }
    }
}
