using System.Text;
using Microsoft.Extensions.Options;
using WishNinja.Configuration;
using WishNinja.Services;
using Xunit;

namespace WishNinja.Tests;

public class ImageServiceTests : IDisposable
{
    private readonly string _tempDir;
    private readonly ImageService _svc;

    public ImageServiceTests()
    {
        _tempDir = Path.Combine(Path.GetTempPath(), "wishninja-tests-" + Guid.NewGuid().ToString("N"));
        var options = Options.Create(new WishNinjaOptions
        {
            DataPath = _tempDir,
            Uploads = new UploadOptions { MaxBytes = 1024 }, // 1 KB cap for the test
        });
        _svc = new ImageService(options, new StubHttpClientFactory());
    }

    private sealed class StubHttpClientFactory : IHttpClientFactory
    {
        public HttpClient CreateClient(string name) => new();
    }

    [Theory]
    [InlineData("image/png", true)]
    [InlineData("image/jpeg", true)]
    [InlineData("image/webp", true)]
    [InlineData("image/gif", true)]
    [InlineData("application/pdf", false)]
    [InlineData("text/html", false)]
    [InlineData(null, false)]
    public void IsAllowedContentType_enforces_allowlist(string? contentType, bool expected) =>
        Assert.Equal(expected, _svc.IsAllowedContentType(contentType));

    [Fact]
    public async Task SaveAsync_rejects_disallowed_type()
    {
        using var stream = new MemoryStream(Encoding.UTF8.GetBytes("not an image"));
        var result = await _svc.SaveAsync(stream, "application/pdf");
        Assert.False(result.Succeeded);
        Assert.Null(result.FileName);
    }

    [Fact]
    public async Task SaveAsync_rejects_oversize_file_and_cleans_up()
    {
        using var stream = new MemoryStream(new byte[2048]); // exceeds 1 KB cap
        var result = await _svc.SaveAsync(stream, "image/png");
        Assert.False(result.Succeeded);
        Assert.Empty(Directory.GetFiles(_svc.UploadsDirectory)); // partial file removed
    }

    [Theory]
    [InlineData("not-a-url")]
    [InlineData("ftp://example.com/x.png")]
    [InlineData("file:///etc/passwd")]
    public async Task SaveFromUrlAsync_rejects_non_http_urls(string url)
    {
        var result = await _svc.SaveFromUrlAsync(url);
        Assert.False(result.Succeeded);
        Assert.Empty(Directory.GetFiles(_svc.UploadsDirectory));
    }

    [Fact]
    public async Task SaveAsync_writes_allowed_file_with_guid_name()
    {
        using var stream = new MemoryStream(new byte[512]);
        var result = await _svc.SaveAsync(stream, "image/png");
        Assert.True(result.Succeeded);
        Assert.EndsWith(".png", result.FileName);
        Assert.True(File.Exists(Path.Combine(_svc.UploadsDirectory, result.FileName!)));
    }

    public void Dispose()
    {
        if (Directory.Exists(_tempDir)) Directory.Delete(_tempDir, recursive: true);
    }
}
