using System.Security.Claims;
using JobTrackerApi.Controllers;
using JobTrackerApi.Services.EmailProviders;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class EmailControllerTests
{
    [Fact]
    public async Task Provider_status_is_owner_scoped_and_does_not_claim_send_support()
    {
        var gmail = new FakeProvider("gmail", new EmailConnectionInfo("gmail", "owner@gmail.test", CanSend: true));
        var outlook = new FakeProvider("microsoft", null);
        var controller = CreateController(gmail, outlook);

        var result = await controller.GetProviders(CancellationToken.None);

        var ok = Assert.IsType<OkObjectResult>(result.Result);
        var statuses = Assert.IsAssignableFrom<IReadOnlyList<EmailController.ProviderStatus>>(ok.Value);
        Assert.Equal("user-1", gmail.LastOwnerUserId);
        Assert.Collection(statuses,
            status =>
            {
                Assert.Equal("Gmail", status.DisplayName);
                Assert.True(status.Connected);
                Assert.True(status.CanRead);
                Assert.True(status.CanSend);
            },
            status =>
            {
                Assert.Equal("Outlook", status.DisplayName);
                Assert.False(status.Connected);
                Assert.False(status.CanRead);
                Assert.False(status.CanSend);
            });
    }

    [Fact]
    public async Task Search_rejects_unknown_or_disconnected_provider()
    {
        var controller = CreateController(new FakeProvider("gmail", null));

        var unknown = await controller.Search("unknown", null, 25, CancellationToken.None);
        Assert.IsType<BadRequestObjectResult>(unknown.Result);

        var disconnected = await controller.Search("gmail", null, 25, CancellationToken.None);
        Assert.IsType<ConflictObjectResult>(disconnected.Result);
    }

    [Fact]
    public async Task Message_detail_returns_plain_text_without_provider_html()
    {
        var provider = new FakeProvider("gmail", new EmailConnectionInfo("gmail", "owner@gmail.test"));
        var controller = CreateController(provider);

        var result = await controller.GetMessage("gmail", "message-1", CancellationToken.None);

        var ok = Assert.IsType<OkObjectResult>(result.Result);
        var detail = Assert.IsType<EmailMessageDetailDto>(ok.Value);
        Assert.Equal("Safe plain text", detail.BodyText);
        Assert.DoesNotContain("script", System.Text.Json.JsonSerializer.Serialize(detail), StringComparison.OrdinalIgnoreCase);
        Assert.Equal("user-1", provider.LastOwnerUserId);
    }

    private static EmailController CreateController(params IEmailProvider[] providers)
    {
        var db = TestHostFactory.CreateInMemoryDb();
        var controller = new EmailController(new EmailProviderRegistry(providers), db, new EmailSendAttemptStore(db, TimeProvider.System), NullLogger<EmailController>.Instance);
        controller.ControllerContext = new ControllerContext
        {
            HttpContext = new DefaultHttpContext
            {
                User = new ClaimsPrincipal(new ClaimsIdentity(
                    new[] { new Claim(ClaimTypes.NameIdentifier, "user-1") },
                    "test"))
            }
        };
        return controller;
    }

    private sealed class FakeProvider(string providerKey, EmailConnectionInfo? connection) : IEmailProvider
    {
        public string ProviderKey => providerKey;
        public string? LastOwnerUserId { get; private set; }

        public Task<EmailConnectionInfo?> GetConnectionAsync(string ownerUserId, CancellationToken cancellationToken)
        {
            LastOwnerUserId = ownerUserId;
            return Task.FromResult(connection);
        }

        public Task<IReadOnlyList<EmailMessageSummary>> SearchAsync(string ownerUserId, string? query, int maxResults, CancellationToken cancellationToken)
            => Task.FromResult<IReadOnlyList<EmailMessageSummary>>(Array.Empty<EmailMessageSummary>());

        public Task<IReadOnlyList<EmailMessageSummary>> ListThreadMessagesAsync(string ownerUserId, string threadId, CancellationToken cancellationToken)
            => Task.FromResult<IReadOnlyList<EmailMessageSummary>>(Array.Empty<EmailMessageSummary>());

        public Task<EmailMessageDetail> GetMessageAsync(string ownerUserId, string messageId, CancellationToken cancellationToken)
        {
            LastOwnerUserId = ownerUserId;
            return Task.FromResult(new EmailMessageDetail(
                messageId,
                "thread-1",
                "Interview",
                "recruiter@example.test",
                "owner@gmail.test",
                DateTimeOffset.UtcNow,
                "Snippet",
                "Safe plain text",
                "<script>unsafe()</script>",
                Array.Empty<string>(),
                Array.Empty<EmailAttachmentRef>()));
        }

        public Task<EmailDeliveryResult> SendAsync(string ownerUserId, EmailDeliveryRequest request, CancellationToken cancellationToken) =>
            Task.FromResult(new EmailDeliveryResult("message-1", "thread-1"));
    }
}
