using MediatR;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Application.App.Tenants.Targeting;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
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 MarkAnnouncementAsReadCommandHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantAnnouncementReadRepository readRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor? currentUserAccessor = null,
    IAdminAuthService? adminAuthService = null,
    IMiniAuthService? miniAuthService = null)
    : IRequestHandler<MarkAnnouncementAsReadCommand, TenantAnnouncementDto?>
{
    /// <summary>
    /// 标记公告已读。
    /// </summary>
    /// <param name="request">标记命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>公告 DTO 或 null。</returns>
    public async Task<TenantAnnouncementDto?> Handle(MarkAnnouncementAsReadCommand request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();

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

        // 2. 仅允许已发布且在有效期内的公告标记已读
        var now = DateTime.UtcNow;
        if (announcement.Status != AnnouncementStatus.Published)
        {
            return null;
        }

        if (announcement.EffectiveFrom > now || (announcement.EffectiveTo.HasValue && announcement.EffectiveTo.Value < now))
        {
            return null;
        }

        if (announcement.ScheduledPublishAt.HasValue && announcement.ScheduledPublishAt.Value > now)
        {
            return null;
        }

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

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

        // 4. 确定用户标识
        var userId = targetContext.UserId == 0 ? (long?)null : targetContext.UserId;
        var existing = await readRepository.FindAsync(tenantId, announcement.Id, userId, cancellationToken);

        if (existing == null && userId.HasValue)
        {
            existing = await readRepository.FindAsync(tenantId, announcement.Id, null, cancellationToken);
        }

        // 5. 如未读则写入已读记录
        if (existing == null)
        {
            var record = new TenantAnnouncementRead
            {
                TenantId = tenantId,
                AnnouncementId = announcement.Id,
                UserId = userId,
                ReadAt = now
            };

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

        return announcement.ToDto(true, existing.ReadAt);
    }
}
