using MediatR;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Application.App.Tenants.Queries;
using TakeoutSaaS.Application.App.Tenants.Targeting;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 公告详情查询处理器。
/// </summary>
public sealed class GetAnnouncementByIdQueryHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantAnnouncementReadRepository readRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor? currentUserAccessor = null,
    IAdminAuthService? adminAuthService = null,
    IMiniAuthService? miniAuthService = null)
    : IRequestHandler<GetAnnouncementByIdQuery, TenantAnnouncementDto?>
{
    /// <summary>
    /// 查询公告详情。
    /// </summary>
    /// <param name="request">查询请求。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>公告 DTO 或 null。</returns>
    public async Task<TenantAnnouncementDto?> Handle(GetAnnouncementByIdQuery request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();

        // 1. 查询公告主体
        var announcement = await announcementRepository.FindByIdAsync(tenantId, request.AnnouncementId, cancellationToken);
        if (announcement == null)
        {
            return null;
        }

        // 2. 目标受众过滤
        var targetContext = await AnnouncementTargetContextFactory.BuildAsync(
            tenantProvider,
            currentUserAccessor,
            adminAuthService,
            miniAuthService,
            cancellationToken);

        if (!TargetTypeFilter.IsMatch(announcement, targetContext))
        {
            return null;
        }

        // 3. 优先查用户级已读
        var userId = targetContext.UserId;
        var reads = await readRepository.GetByAnnouncementAsync(
            tenantId,
            new[] { announcement.Id },
            userId == 0 ? null : userId,
            cancellationToken);

        if (reads.Count == 0)
        {
            var tenantReads = await readRepository.GetByAnnouncementAsync(tenantId, new[] { announcement.Id }, null, cancellationToken);
            reads = tenantReads;
        }

        var readRecord = reads.FirstOrDefault();
        return announcement.ToDto(readRecord != null, readRecord?.ReadAt);
    }
}
