using JobTrackerApi.Services;
using JobTrackerApi.Services.EmailProviders;
using Moq;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class MicrosoftGraphProviderTests
{
    [Fact]
    public void ProviderKey_is_microsoft()
    {
        var provider = new MicrosoftGraphProvider(Mock.Of<IMicrosoftGraphOAuthService>());
        Assert.Equal("microsoft", provider.ProviderKey);
    }

    [Fact]
    public async Task GetConnectionAsync_maps_mail_address_onto_neutral_shape()
    {
        var graph = new Mock<IMicrosoftGraphOAuthService>();
        graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
            .ReturnsAsync(new JobTrackerApi.Models.MicrosoftGraphConnection { OwnerUserId = "user-1", MailAddress = "user@outlook.test" });

        var provider = new MicrosoftGraphProvider(graph.Object);
        var connection = await provider.GetConnectionAsync("user-1", CancellationToken.None);

        Assert.NotNull(connection);
        Assert.Equal("microsoft", connection!.ProviderKey);
        Assert.Equal("user@outlook.test", connection.Address);
        Assert.False(connection.CanSend);
    }

    [Fact]
    public async Task GetConnectionAsync_reports_send_only_after_mail_send_consent()
    {
        var graph = new Mock<IMicrosoftGraphOAuthService>();
        graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
            .ReturnsAsync(new JobTrackerApi.Models.MicrosoftGraphConnection { OwnerUserId = "user-1", MailAddress = "user@outlook.test", Scope = "Mail.Read Mail.Send" });

        var connection = await new MicrosoftGraphProvider(graph.Object).GetConnectionAsync("user-1", default);

        Assert.True(connection!.CanSend);
    }

    [Fact]
    public async Task GetConnectionAsync_returns_null_when_not_connected()
    {
        var graph = new Mock<IMicrosoftGraphOAuthService>();
        graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
            .ReturnsAsync((JobTrackerApi.Models.MicrosoftGraphConnection?)null);

        var provider = new MicrosoftGraphProvider(graph.Object);
        var connection = await provider.GetConnectionAsync("user-1", CancellationToken.None);

        Assert.Null(connection);
    }

    [Fact]
    public async Task SearchAsync_maps_conversation_id_onto_neutral_thread_id()
    {
        var graph = new Mock<IMicrosoftGraphOAuthService>();
        graph.Setup(service => service.ListMessagesAsync("user-1", "recruiter", 10, It.IsAny<CancellationToken>()))
            .ReturnsAsync(new List<MicrosoftGraphMessageSummary>
            {
                new("msg-1", "conv-1", "Interview", "them@company.test", "me@outlook.test", DateTimeOffset.UtcNow, "snippet")
            });

        var provider = new MicrosoftGraphProvider(graph.Object);
        var results = await provider.SearchAsync("user-1", "recruiter", 10, CancellationToken.None);

        var summary = Assert.Single(results);
        Assert.Equal("msg-1", summary.Id);
        Assert.Equal("conv-1", summary.ThreadId);
        Assert.Equal("Interview", summary.Subject);
    }

    [Fact]
    public async Task GetMessageAsync_maps_attachment_id_onto_neutral_external_attachment_id()
    {
        var graph = new Mock<IMicrosoftGraphOAuthService>();
        graph.Setup(service => service.GetMessageAsync("user-1", "msg-1", It.IsAny<CancellationToken>()))
            .ReturnsAsync(new MicrosoftGraphMessageDetail(
                "msg-1", "conv-1", "Offer", "them@company.test", "me@outlook.test", DateTimeOffset.UtcNow, "snippet",
                "body text", "<p>body</p>", new List<string> { "Inbox" },
                new List<MicrosoftGraphMessageAttachment> { new("resume.pdf", "application/pdf", 1024, "graph-att-1", false) }));

        var provider = new MicrosoftGraphProvider(graph.Object);
        var detail = await provider.GetMessageAsync("user-1", "msg-1", CancellationToken.None);

        Assert.Equal("conv-1", detail.ThreadId);
        var attachment = Assert.Single(detail.Attachments);
        Assert.Equal("resume.pdf", attachment.FileName);
        Assert.Equal("graph-att-1", attachment.ExternalAttachmentId);
    }
}
