using MediatR;
using TakeoutSaaS.Application.App.Coupons.PunchCard.Dto;
using TakeoutSaaS.Application.App.Coupons.PunchCard.Queries;
using TakeoutSaaS.Domain.Coupons.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Coupons.PunchCard.Handlers;

/// <summary>
/// 次卡使用记录列表查询处理器。
/// </summary>
public sealed class GetPunchCardUsageRecordListQueryHandler(
    IPunchCardRepository repository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetPunchCardUsageRecordListQuery, PunchCardUsageRecordListResultDto>
{
    /// <inheritdoc />
    public async Task<PunchCardUsageRecordListResultDto> Handle(
        GetPunchCardUsageRecordListQuery request,
        CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var page = Math.Max(1, request.Page);
        var pageSize = Math.Clamp(request.PageSize, 1, 500);
        var normalizedStatus = PunchCardMapping.ParseUsageStatusFilter(request.Status);

        var (records, totalCount) = await repository.SearchUsageRecordsAsync(
            tenantId,
            request.StoreId,
            request.TemplateId,
            request.Keyword,
            normalizedStatus,
            page,
            pageSize,
            cancellationToken);

        var instanceIds = records.Select(item => item.PunchCardInstanceId).Distinct().ToList();
        var instances = await repository.GetInstancesByIdsAsync(
            tenantId,
            request.StoreId,
            instanceIds,
            cancellationToken);

        var instanceMap = instances.ToDictionary(item => item.Id, item => item);

        var templateIds = records.Select(item => item.PunchCardTemplateId)
            .Concat(instances.Select(item => item.PunchCardTemplateId))
            .Distinct()
            .ToList();

        var templates = await repository.GetTemplatesByIdsAsync(
            tenantId,
            request.StoreId,
            templateIds,
            cancellationToken);

        var templateMap = templates.ToDictionary(item => item.Id, item => item);

        var nowUtc = DateTime.UtcNow;
        var mappedRecords = records
            .Select(record =>
            {
                instanceMap.TryGetValue(record.PunchCardInstanceId, out var instance);
                templateMap.TryGetValue(record.PunchCardTemplateId, out var template);
                return PunchCardDtoFactory.ToUsageRecordDto(record, instance, template, nowUtc);
            })
            .ToList();

        var usageStats = await repository.GetUsageStatsAsync(
            tenantId,
            request.StoreId,
            request.TemplateId,
            nowUtc,
            cancellationToken);

        var (templateRows, _) = await repository.SearchTemplatesAsync(
            tenantId,
            request.StoreId,
            null,
            null,
            1,
            500,
            cancellationToken);

        var templateOptions = templateRows
            .OrderBy(item => item.Name, StringComparer.Ordinal)
            .Select(item => new PunchCardTemplateOptionDto
            {
                TemplateId = item.Id,
                Name = item.Name
            })
            .ToList();

        return new PunchCardUsageRecordListResultDto
        {
            Items = mappedRecords,
            Page = page,
            PageSize = pageSize,
            TotalCount = totalCount,
            Stats = PunchCardDtoFactory.ToUsageStatsDto(usageStats),
            TemplateOptions = templateOptions
        };
    }
}
