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

namespace JobTrackerApi.Controllers;

/// <summary>
/// Generic IMAP connection lifecycle for mailboxes with no dedicated OAuth provider. Unlike
/// Gmail/Microsoft, there's no OAuth redirect — the caller submits host/username/password once,
/// <see cref="IImapService"/> verifies them by connecting, then encrypts and stores them.
/// </summary>
[ApiController]
[Route("api/imap")]
[Authorize]
public sealed class ImapController : ControllerBase
{
    private readonly IImapService _imap;

    public ImapController(IImapService imap)
    {
        _imap = imap;
    }

    public sealed record ImapConnectRequest(string Host, int Port, bool UseSsl, string Username, string Password);

    public sealed record ImapConnectionStatusDto(
        bool Connected,
        string? Host,
        int? Port,
        bool? UseSsl,
        string? Username,
        DateTimeOffset? ConnectedAt,
        DateTimeOffset? LastSyncedAt,
        DateTimeOffset? LastSyncAttemptedAt,
        DateTimeOffset? LastSyncSucceededAt,
        string? LastSyncMode,
        string? LastSyncSource,
        string? LastSyncStatus,
        string? LastSyncError);

    [HttpGet("status")]
    public async Task<ActionResult<ImapConnectionStatusDto>> Status(CancellationToken cancellationToken)
    {
        var ownerUserId = GetRequiredOwnerUserId();
        var connection = await _imap.GetConnectionAsync(ownerUserId, cancellationToken);
        return Ok(new ImapConnectionStatusDto(
            connection is not null,
            connection?.Host,
            connection?.Port,
            connection?.UseSsl,
            connection?.Username,
            connection?.ConnectedAt,
            connection?.LastSyncedAt,
            connection?.LastSyncAttemptedAt,
            connection?.LastSyncSucceededAt,
            connection?.LastSyncMode,
            connection?.LastSyncSource,
            connection?.LastSyncStatus,
            connection?.LastSyncError));
    }

    [HttpPost("connect")]
    public async Task<IActionResult> Connect([FromBody] ImapConnectRequest request, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(request.Host)) return BadRequest("Host is required.");
        if (request.Port <= 0 || request.Port > 65535) return BadRequest("Valid port is required.");
        if (string.IsNullOrWhiteSpace(request.Username)) return BadRequest("Username is required.");
        if (string.IsNullOrWhiteSpace(request.Password)) return BadRequest("Password is required.");

        var ownerUserId = GetRequiredOwnerUserId();
        try
        {
            var result = await _imap.ConnectAsync(ownerUserId, request.Host, request.Port, request.UseSsl, request.Username, request.Password, cancellationToken);
            return Ok(new { username = result.Username });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(ex.Message);
        }
    }

    [HttpDelete("connection")]
    public async Task<IActionResult> Disconnect(CancellationToken cancellationToken)
    {
        var ownerUserId = GetRequiredOwnerUserId();
        await _imap.DisconnectAsync(ownerUserId, cancellationToken);
        return NoContent();
    }

    private string GetRequiredOwnerUserId()
    {
        return User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub")
            ?? throw new InvalidOperationException("Authenticated user id is missing.");
    }
}
