using System.Net;
using YMhut.Box.Core.Media;

namespace YMhut.Box.Tests;

[TestClass]
public sealed class RemoteMediaResolverTests
{
    [TestMethod]
    public async Task ResolvesRedirectToDirectMedia()
    {
        var resolver = CreateResolver(request =>
        {
            if (request.RequestUri?.AbsolutePath == "/api")
            {
                return Redirect("/media/demo.mp4");
            }

            return Text(HttpStatusCode.OK, string.Empty, "video/mp4");
        });

        var result = await resolver.ResolveMediaAsync("https://example.test/api", RemoteMediaKind.Video, cacheBust: false);

        Assert.AreEqual("https://example.test/media/demo.mp4", result.Uri.AbsoluteUri);
        Assert.IsTrue(result.IsDirectMedia);
        Assert.AreEqual("video/mp4", result.ContentType);
        Assert.AreEqual(".mp4", result.SuggestedExtension);
    }

    [TestMethod]
    public async Task ExtractsPlainTextUrl()
    {
        var resolver = CreateResolver(request =>
        {
            if (request.RequestUri?.Host == "cdn.test")
            {
                return Text(HttpStatusCode.OK, string.Empty, "video/mp4");
            }

            return Text(HttpStatusCode.OK, "https://cdn.test/random/clip.mp4", "text/plain");
        });

        var result = await resolver.ResolveMediaAsync("https://example.test/api", RemoteMediaKind.Video, cacheBust: false);

        Assert.AreEqual("https://cdn.test/random/clip.mp4", result.Uri.AbsoluteUri);
        Assert.IsTrue(result.IsDirectMedia);
        Assert.AreEqual(".mp4", result.SuggestedExtension);
    }

    [TestMethod]
    public async Task ExtractsNestedJsonUrl()
    {
        var resolver = CreateResolver(request =>
        {
            if (request.RequestUri?.Host == "cdn.test")
            {
                return Text(HttpStatusCode.OK, string.Empty, "image/webp");
            }

            return Text(HttpStatusCode.OK, """
            {
              "data": {
                "url": "https://cdn.test/images/pic.webp"
              }
            }
            """, "application/json");
        });

        var result = await resolver.ResolveMediaAsync("https://example.test/api", RemoteMediaKind.Image, cacheBust: false);

        Assert.AreEqual("https://cdn.test/images/pic.webp", result.Uri.AbsoluteUri);
        Assert.IsTrue(result.IsDirectMedia);
        Assert.AreEqual(".webp", result.SuggestedExtension);
    }

    [TestMethod]
    public async Task KeepsHtmlWithoutMediaUrlAsNonDirect()
    {
        var resolver = CreateResolver(_ => Text(HttpStatusCode.OK, "<html><body>No media here</body></html>", "text/html"));

        var result = await resolver.ResolveMediaAsync("https://example.test/page", RemoteMediaKind.Video, cacheBust: false);

        Assert.AreEqual("https://example.test/page", result.Uri.AbsoluteUri);
        Assert.IsFalse(result.IsDirectMedia);
        Assert.AreEqual("text/html", result.ContentType);
    }

    [TestMethod]
    public async Task TreatsDirectMediaContentTypeAsPlayable()
    {
        var resolver = CreateResolver(_ => Text(HttpStatusCode.OK, string.Empty, "audio/mpeg"));

        var result = await resolver.ResolveMediaAsync("https://example.test/random", RemoteMediaKind.Audio, cacheBust: false);

        Assert.AreEqual("https://example.test/random", result.Uri.AbsoluteUri);
        Assert.IsTrue(result.IsDirectMedia);
        Assert.AreEqual(".mp3", result.SuggestedExtension);
    }

    private static RemoteMediaResolver CreateResolver(Func<HttpRequestMessage, HttpResponseMessage> responseFactory)
    {
        return new RemoteMediaResolver(() => new StubHttpHandler(responseFactory));
    }

    private static HttpResponseMessage Redirect(string location)
    {
        var response = new HttpResponseMessage(HttpStatusCode.Redirect);
        response.Headers.Location = new Uri(location, UriKind.RelativeOrAbsolute);
        return response;
    }

    private static HttpResponseMessage Text(HttpStatusCode statusCode, string content, string contentType)
    {
        return new HttpResponseMessage(statusCode)
        {
            Content = new StringContent(content, System.Text.Encoding.UTF8, contentType)
        };
    }

    private sealed class StubHttpHandler(Func<HttpRequestMessage, HttpResponseMessage> responseFactory) : HttpMessageHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = responseFactory(request);
            response.RequestMessage = request;
            return Task.FromResult(response);
        }
    }
}
