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.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 未读公告查询处理器。
/// </summary>
public sealed class GetUnreadAnnouncementsQueryHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor? currentUserAccessor = null,
    IAdminAuthService? adminAuthService = null,
    IMiniAuthService? miniAuthService = null)
    : IRequestHandler<GetUnreadAnnouncementsQuery, PagedResult<TenantAnnouncementDto>>
{
    /// <inheritdoc />
    public async Task<PagedResult<TenantAnnouncementDto>> Handle(GetUnreadAnnouncementsQuery request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var userId = currentUserAccessor?.UserId ?? 0;
        var now = DateTime.UtcNow;

        // 1. 查询未读公告（已发布/启用/有效期内）
        var announcements = await announcementRepository.SearchUnreadAsync(
            tenantId,
            userId == 0 ? null : userId,
            AnnouncementStatus.Published,
            true,
            now,
            cancellationToken);

        announcements = announcements
            .Where(x => x.ScheduledPublishAt == null || x.ScheduledPublishAt <= now)
            .ToList();

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

        var filtered = announcements
            .Where(a => TargetTypeFilter.IsMatch(a, targetContext))
            .ToList();

        // 3. 排序与分页
        var ordered = filtered
            .OrderByDescending(x => x.Priority)
            .ThenByDescending(x => x.EffectiveFrom)
            .ToList();

        var page = request.Page <= 0 ? 1 : request.Page;
        var size = request.PageSize <= 0 ? 20 : request.PageSize;
        var pageItems = ordered
            .Skip((page - 1) * size)
            .Take(size)
            .ToList();

        var items = pageItems
            .Select(x => x.ToDto(false, null))
            .ToList();

        return new PagedResult<TenantAnnouncementDto>(items, page, size, ordered.Count);
    }
}
