using JobTrackerApi.Controllers;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Moq;
using System.Reflection;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class PublicCvControllerTests
{
    [Fact]
    public void Pdf_download_is_rate_limited()
    {
        var attribute = typeof(PublicCvController).GetMethod(nameof(PublicCvController.DownloadPdf))!
            .GetCustomAttribute<EnableRateLimitingAttribute>();

        Assert.Equal("public-pdf", attribute?.PolicyName);
    }

    [Fact]
    public async Task Pdf_download_uses_the_public_variant_render()
    {
        var user = new ApplicationUser { Id = "owner-1", FirstName = "Ada", LastName = "Lovelace" };
        var variants = new Mock<ICvVariantService>();
        var pdf = new Mock<ICvPdfExporter>();
        var render = new ThemedCvRenderResult("modern", "ada-cv.pdf", "<html>CV</html>");
        variants.Setup(x => x.GetPublicOwnerAsync("public-slug", It.IsAny<CancellationToken>())).ReturnsAsync(user.Id);
        variants.Setup(x => x.RenderPublicAsync("public-slug", It.IsAny<CvRenderPerson>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync((render, user.Id));
        pdf.Setup(x => x.ExportAsync(It.IsAny<string>(), It.IsAny<TailoredCvRenderResult>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(new CvPdfArtifact("ada-cv.pdf", "unused", [1, 2, 3]));

        var controller = new PublicCvController(TestHostFactory.CreateUserManager(user).Object, variants.Object, pdf.Object);

        var result = Assert.IsType<FileContentResult>(await controller.DownloadPdf("public-slug", CancellationToken.None));

        Assert.Equal("application/pdf", result.ContentType);
        Assert.Equal("ada-cv.pdf", result.FileDownloadName);
        Assert.Equal([1, 2, 3], result.FileContents);
        pdf.Verify(x => x.ExportAsync(
            user.Id,
            It.Is<TailoredCvRenderResult>(value => value.TemplateId == "modern" && value.Html == "<html>CV</html>"),
            It.IsAny<CancellationToken>()), Times.Once);
    }

    [Fact]
    public async Task Pdf_download_does_not_render_an_unknown_or_private_slug()
    {
        var variants = new Mock<ICvVariantService>();
        variants.Setup(x => x.GetPublicOwnerAsync("private-slug", It.IsAny<CancellationToken>())).ReturnsAsync((string?)null);
        var pdf = new Mock<ICvPdfExporter>();
        var controller = new PublicCvController(TestHostFactory.CreateUserManager().Object, variants.Object, pdf.Object);

        Assert.IsType<NotFoundResult>(await controller.DownloadPdf("private-slug", CancellationToken.None));
        variants.Verify(x => x.RenderPublicAsync(It.IsAny<string>(), It.IsAny<CvRenderPerson>(), It.IsAny<CancellationToken>()), Times.Never);
        pdf.VerifyNoOtherCalls();
    }
}
