using MediatR;
using TakeoutSaaS.Application.App.Tenants.Dto;
using TakeoutSaaS.Application.App.Tenants.Queries;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Security;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 公告分页查询处理器。
/// </summary>
public sealed class SearchTenantAnnouncementsQueryHandler(
    ITenantAnnouncementRepository announcementRepository,
    ITenantAnnouncementReadRepository announcementReadRepository,
    ICurrentUserAccessor? currentUserAccessor = null)
    : IRequestHandler<SearchTenantAnnouncementsQuery, PagedResult<TenantAnnouncementDto>>
{
    /// <summary>
    /// 分页查询公告列表。
    /// </summary>
    /// <param name="request">查询条件。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>分页结果。</returns>
    public async Task<PagedResult<TenantAnnouncementDto>> Handle(SearchTenantAnnouncementsQuery request, CancellationToken cancellationToken)
    {
        // 1. 过滤有效期条件
        var effectiveAt = request.OnlyEffective == true ? DateTime.UtcNow : (DateTime?)null;
        var announcements = await announcementRepository.SearchAsync(request.TenantId, request.AnnouncementType, request.IsActive, effectiveAt, cancellationToken);

        // 2. 排序（优先级/时间）
        var ordered = announcements
            .OrderByDescending(x => x.Priority)
            .ThenByDescending(x => x.CreatedAt)
            .ToList();

        // 3. 计算分页参数
        var page = request.Page <= 0 ? 1 : request.Page;
        var size = request.PageSize <= 0 ? 20 : request.PageSize;

        // 4. 分页
        var pageItems = ordered
            .Skip((page - 1) * size)
            .Take(size)
            .ToList();

        // 5. 构建已读映射
        var announcementIds = pageItems.Select(x => x.Id).ToArray();
        var userId = currentUserAccessor?.UserId ?? 0;

        var readMap = new Dictionary<long, (bool isRead, DateTime? readAt)>();
        if (announcementIds.Length > 0)
        {
            // 优先查询当前用户维度的已读，其次租户级已读（UserId null）
            var reads = new List<Domain.Tenants.Entities.TenantAnnouncementRead>();
            if (userId != 0)
            {
                var userReads = await announcementReadRepository.GetByAnnouncementAsync(request.TenantId, announcementIds, userId, cancellationToken);
                reads.AddRange(userReads);
            }

            var tenantReads = await announcementReadRepository.GetByAnnouncementAsync(request.TenantId, announcementIds, null, cancellationToken);
            reads.AddRange(tenantReads);

            foreach (var read in reads.OrderByDescending(x => x.ReadAt))
            {
                // 若已存在用户级标记，跳过租户级覆盖
                if (readMap.ContainsKey(read.AnnouncementId) && read.UserId.HasValue)
                {
                    continue;
                }

                readMap[read.AnnouncementId] = (true, read.ReadAt);
            }
        }

        // 6. 映射 DTO 并带上已读状态
        var items = pageItems
            .Select(a =>
            {
                readMap.TryGetValue(a.Id, out var read);
                return a.ToDto(read.isRead, read.readAt);
            })
            .ToList();

        // 7. 返回分页结果
        return new PagedResult<TenantAnnouncementDto>(items, page, size, ordered.Count);
    }
}
