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

namespace JobTrackerApi.Tests;

public sealed class ImapProviderTests
{
    [Fact]
    public void ProviderKey_is_imap()
    {
        var provider = new ImapProvider(Mock.Of<IImapService>());
        Assert.Equal("imap", provider.ProviderKey);
    }

    [Fact]
    public async Task GetConnectionAsync_maps_username_onto_neutral_shape()
    {
        var imap = new Mock<IImapService>();
        imap.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
            .ReturnsAsync(new JobTrackerApi.Models.ImapConnection { OwnerUserId = "user-1", Username = "user@example.test" });

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

        Assert.NotNull(connection);
        Assert.Equal("imap", connection!.ProviderKey);
        Assert.Equal("user@example.test", connection.Address);
    }

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

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

        Assert.Null(connection);
    }

    [Fact]
    public async Task SearchAsync_maps_thread_key_onto_neutral_thread_id()
    {
        var imap = new Mock<IImapService>();
        imap.Setup(service => service.ListMessagesAsync("user-1", "recruiter", 10, It.IsAny<CancellationToken>()))
            .ReturnsAsync(new List<ImapMessageSummary>
            {
                new("42", "root-msg-id@example.test", "Interview", "them@company.test", "me@example.test", DateTimeOffset.UtcNow, "snippet")
            });

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

        var summary = Assert.Single(results);
        Assert.Equal("42", summary.Id);
        Assert.Equal("root-msg-id@example.test", summary.ThreadId);
        Assert.Equal("Interview", summary.Subject);
    }

    [Fact]
    public async Task GetMessageAsync_maps_content_id_onto_neutral_external_attachment_id()
    {
        var imap = new Mock<IImapService>();
        imap.Setup(service => service.GetMessageAsync("user-1", "42", It.IsAny<CancellationToken>()))
            .ReturnsAsync(new ImapMessageDetail(
                "42", "root-msg-id@example.test", "Offer", "them@company.test", "me@example.test", DateTimeOffset.UtcNow, "snippet",
                "body text", "<p>body</p>", new List<string>(),
                new List<ImapMessageAttachment> { new("resume.pdf", "application/pdf", 1024, "cid-1", false) }));

        var provider = new ImapProvider(imap.Object);
        var detail = await provider.GetMessageAsync("user-1", "42", CancellationToken.None);

        Assert.Equal("root-msg-id@example.test", detail.ThreadId);
        var attachment = Assert.Single(detail.Attachments);
        Assert.Equal("resume.pdf", attachment.FileName);
        Assert.Equal("cid-1", attachment.ExternalAttachmentId);
    }
}
