#nullable enable
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.SupportAlerts;
using Baya.Application.Models.Common;
using Baya.Application.Models.SupportAlerts;
using Baya.Domain.Entities.SupportAlerts;
using Microsoft.EntityFrameworkCore;

namespace Baya.Infrastructure.Persistence.Services.SupportAlerts;

/// <summary>
/// Internal support-alert worklist store. Never exposed on a user-facing route. Status is forward-only:
/// an alert can be assigned or resolved from <c>open</c>, and resolved from <c>assigned</c>, but a
/// resolved alert is terminal.
/// </summary>
internal sealed class SupportAlertService(ApplicationDbContext db, IDateTimeProvider dateTimeProvider) : ISupportAlertService
{
    public async ValueTask<long> RaiseAsync(
        string type,
        string entityType,
        string entityId,
        string severity,
        long? bookingId = null,
        long? reviewId = null,
        CancellationToken cancellationToken = default)
    {
        var alert = new SupportAlert
        {
            Type = type,
            EntityType = entityType,
            EntityId = entityId,
            Severity = severity,
            Status = SupportAlertStatus.Open,
            BookingId = bookingId,
            ReviewId = reviewId
        };

        db.Set<SupportAlert>().Add(alert);
        await db.SaveChangesAsync(cancellationToken);
        return alert.Id;
    }

    public async ValueTask<bool> AssignAsync(long alertId, int ownerUserId, CancellationToken cancellationToken = default)
    {
        var alert = await db.Set<SupportAlert>().FirstOrDefaultAsync(a => a.Id == alertId, cancellationToken);
        if (alert is null || alert.Status == SupportAlertStatus.Resolved)
            return false;

        alert.OwnerUserId = ownerUserId;
        alert.Status = SupportAlertStatus.Assigned;
        await db.SaveChangesAsync(cancellationToken);
        return true;
    }

    public async ValueTask<bool> ResolveAsync(long alertId, string note, CancellationToken cancellationToken = default)
    {
        var alert = await db.Set<SupportAlert>().FirstOrDefaultAsync(a => a.Id == alertId, cancellationToken);
        if (alert is null || alert.Status == SupportAlertStatus.Resolved)
            return false;

        alert.Status = SupportAlertStatus.Resolved;
        alert.ResolutionNote = note;
        alert.ResolvedAt = dateTimeProvider.UtcNow;
        await db.SaveChangesAsync(cancellationToken);
        return true;
    }

    public async ValueTask<PagedResult<SupportAlertDto>> ListAsync(
        string? type,
        string? status,
        int? ownerUserId,
        int page,
        int pageSize,
        CancellationToken cancellationToken = default)
    {
        var query = db.Set<SupportAlert>().AsNoTracking().AsQueryable();

        if (!string.IsNullOrWhiteSpace(type))
            query = query.Where(a => a.Type == type);
        if (!string.IsNullOrWhiteSpace(status))
            query = query.Where(a => a.Status == status);
        if (ownerUserId is { } owner)
            query = query.Where(a => a.OwnerUserId == owner);

        // Id is a monotonic identity → newest-first and deterministic (no timestamp ties).
        query = query.OrderByDescending(a => a.Id);

        var total = await query.CountAsync(cancellationToken);
        var items = await query
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(a => new SupportAlertDto(
                a.Id, a.Type, a.Severity, a.Status, a.EntityType, a.EntityId,
                a.BookingId, a.ReviewId, a.OwnerUserId, a.ResolutionNote, a.ResolvedAt, a.CreatedAt))
            .ToListAsync(cancellationToken);

        return new PagedResult<SupportAlertDto>(items, total, page, pageSize);
    }
}
