using System.Security.Claims;
using JobTrackerApi.Services.EmailProviders;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace JobTrackerApi.Controllers;

public sealed record EmailMessageDetailDto(
    string Id,
    string ThreadId,
    string Subject,
    string From,
    string To,
    DateTimeOffset? Date,
    string Snippet,
    string BodyText,
    IReadOnlyList<string> Labels,
    IReadOnlyList<EmailAttachmentRef> Attachments);

[ApiController]
[Route("api/email")]
[Authorize(AuthenticationSchemes = "local")]
public sealed class EmailController(IEmailProviderRegistry providers) : ControllerBase
{
    public sealed record ProviderStatus(string Provider, string DisplayName, bool Connected, string? Address, bool CanRead, bool CanSend);
    [HttpGet("providers")]
    public async Task<ActionResult<IReadOnlyList<ProviderStatus>>> GetProviders(CancellationToken cancellationToken)
    {
        var ownerUserId = GetOwnerUserId();
        if (ownerUserId is null) return Unauthorized();

        var statuses = new List<ProviderStatus>(providers.All.Count);
        foreach (var provider in providers.All)
        {
            var connection = await provider.GetConnectionAsync(ownerUserId, cancellationToken);
            statuses.Add(new ProviderStatus(
                provider.ProviderKey,
                GetDisplayName(provider.ProviderKey),
                connection is not null,
                connection?.Address,
                CanRead: connection is not null,
                CanSend: false));
        }

        return Ok(statuses);
    }

    [HttpGet("messages")]
    public async Task<ActionResult<IReadOnlyList<EmailMessageSummary>>> Search(
        [FromQuery] string provider,
        [FromQuery] string? q,
        [FromQuery] int limit = 25,
        CancellationToken cancellationToken = default)
    {
        var resolved = providers.Get(provider);
        if (resolved is null) return BadRequest("Unknown email provider.");

        var ownerUserId = GetOwnerUserId();
        if (ownerUserId is null) return Unauthorized();
        if (await resolved.GetConnectionAsync(ownerUserId, cancellationToken) is null)
            return Conflict(new ProblemDetails { Title = "Email provider is not connected." });

        return Ok(await resolved.SearchAsync(ownerUserId, q, Math.Clamp(limit, 1, 100), cancellationToken));
    }

    [HttpGet("thread")]
    public async Task<ActionResult<IReadOnlyList<EmailMessageSummary>>> GetThread(
        [FromQuery] string provider,
        [FromQuery] string threadId,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(threadId)) return BadRequest("threadId is required.");
        var resolved = providers.Get(provider);
        if (resolved is null) return BadRequest("Unknown email provider.");

        var ownerUserId = GetOwnerUserId();
        if (ownerUserId is null) return Unauthorized();
        if (await resolved.GetConnectionAsync(ownerUserId, cancellationToken) is null)
            return Conflict(new ProblemDetails { Title = "Email provider is not connected." });

        return Ok(await resolved.ListThreadMessagesAsync(ownerUserId, threadId.Trim(), cancellationToken));
    }

    [HttpGet("message")]
    public async Task<ActionResult<EmailMessageDetailDto>> GetMessage(
        [FromQuery] string provider,
        [FromQuery] string messageId,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(messageId)) return BadRequest("messageId is required.");
        var resolved = providers.Get(provider);
        if (resolved is null) return BadRequest("Unknown email provider.");

        var ownerUserId = GetOwnerUserId();
        if (ownerUserId is null) return Unauthorized();
        if (await resolved.GetConnectionAsync(ownerUserId, cancellationToken) is null)
            return Conflict(new ProblemDetails { Title = "Email provider is not connected." });

        var detail = await resolved.GetMessageAsync(ownerUserId, messageId.Trim(), cancellationToken);
        return Ok(new EmailMessageDetailDto(
            detail.Id,
            detail.ThreadId,
            detail.Subject,
            detail.From,
            detail.To,
            detail.Date,
            detail.Snippet,
            detail.BodyText,
            detail.Labels,
            detail.Attachments));
    }

    private string? GetOwnerUserId() =>
        User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub");

    private static string GetDisplayName(string provider) => provider.ToLowerInvariant() switch
    {
        "gmail" => "Gmail",
        "microsoft" => "Outlook",
        "imap" => "IMAP",
        _ => provider,
    };
}
