using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Nexus.Api.Data;
using Nexus.Api.Models;
using Nexus.Api.Services;

namespace Nexus.Api.Controllers;

[Authorize]
[ApiController]
[Route("api/dashboard/notifications")]
public class NotificationsController(INotificationService notificationService) : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<List<NotificationDto>>> GetNotifications(
        [FromQuery] string forUser = "bao",
        [FromQuery] int limit = 50,
        [FromQuery] bool unreadOnly = false,
        CancellationToken ct = default)
    {
        var notifications = await notificationService.GetForUserAsync(forUser, limit, unreadOnly, ct);
        return Ok(notifications.Select(notification => MapToDto(notification)).ToList());
    }

    [HttpGet("unread-count")]
    public async Task<ActionResult<UnreadCountDto>> GetUnreadCount(
        [FromQuery] string forUser = "bao",
        CancellationToken ct = default)
    {
        var count = await notificationService.GetUnreadCountAsync(forUser, ct);
        return Ok(new UnreadCountDto(count));
    }

    [HttpGet("snapshot")]
    public async Task<ActionResult<NotificationSnapshotDto>> GetSnapshot(
        [FromQuery] string forUser = "bao",
        [FromQuery] int limit = 50,
        [FromQuery] bool unreadOnly = false,
        CancellationToken ct = default)
    {
        return Ok(await notificationService.GetSnapshotAsync(forUser, limit, unreadOnly, ct));
    }

    [HttpPatch("{id:guid}/read")]
    [ProducesResponseType(typeof(NotificationDto), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    public async Task<ActionResult<NotificationDto>> MarkAsRead(
        Guid id,
        CancellationToken ct = default)
    {
        var readResult = await notificationService.MarkAsReadAsync(id, ct);
        var notification = readResult.Notification;
        if (notification is null)
            return NotFound(new ProblemDetails
            {
                Title = "Notification not found",
                Detail = $"Notification '{id}' does not exist.",
                Status = StatusCodes.Status404NotFound
            });

        var primary = new EntityRefDto(
            "notification",
            notification.Id.ToString(),
            notification.Title);
        var affected = notification.TaskId is { } taskId
            ? new[] { new EntityRefDto("task", taskId.ToString()) }
            : [];
        var operation = OperationResultFactory.FromHttpContext(
            HttpContext,
            readResult.Changed ? "completed" : "noop",
            primary,
            revision: readResult.Changed ? 1 : 0,
            affectedRefs: affected);
        return Ok(MapToDto(notification, operation));
    }

    [HttpPatch("read-all")]
    [ProducesResponseType(typeof(NotificationReadAllResultDto), StatusCodes.Status200OK)]
    public async Task<ActionResult<NotificationReadAllResultDto>> MarkAllAsRead(
        [FromQuery] string forUser = "bao",
        CancellationToken ct = default)
    {
        var count = await notificationService.MarkAllAsReadAsync(forUser, ct);
        var operation = OperationResultFactory.FromHttpContext(
            HttpContext,
            count > 0 ? "completed" : "noop",
            new EntityRefDto("notification", "*", "Benachrichtigungen"));
        return Ok(new NotificationReadAllResultDto(count, operation));
    }

    private static NotificationDto MapToDto(
        Notification n,
        OperationResultDto? operation = null) => new(
        n.Id, n.Type, n.Title, n.Message,
        n.ForUser, n.TaskId, n.IsRead, n.CreatedAt, operation);
}
