using MediatR;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Security;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 标记公告已读处理器。
/// </summary>
public sealed class MarkTenantAnnouncementReadCommandHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantAnnouncementReadRepository readRepository,
    ICurrentUserAccessor? currentUserAccessor = null)
    : IRequestHandler<MarkTenantAnnouncementReadCommand, TenantAnnouncementDto?>
{
    /// <summary>
    /// 标记公告已读。
    /// </summary>
    /// <param name="request">标记命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>公告 DTO 或 null。</returns>
    public async Task<TenantAnnouncementDto?> Handle(MarkTenantAnnouncementReadCommand request, CancellationToken cancellationToken)
    {
        // 1. 查询公告
        var announcement = await announcementRepository.FindByIdAsync(request.TenantId, request.AnnouncementId, cancellationToken);
        if (announcement == null)
        {
            return null;
        }

        // 2. 确定用户标识
        var userId = currentUserAccessor?.UserId ?? 0;
        var existing = await readRepository.FindAsync(request.TenantId, request.AnnouncementId, userId == 0 ? null : userId, cancellationToken);

        // 3. 如未读则写入已读记录
        if (existing == null)
        {
            var record = new TenantAnnouncementRead
            {
                TenantId = request.TenantId,
                AnnouncementId = request.AnnouncementId,
                UserId = userId == 0 ? null : userId,
                ReadAt = DateTime.UtcNow
            };

            await readRepository.AddAsync(record, cancellationToken);
            await readRepository.SaveChangesAsync(cancellationToken);
            existing = record;
        }

        // 4. 返回带已读时间的公告 DTO
        return announcement.ToDto(true, existing.ReadAt);
    }
}
