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

namespace TakeoutSaaS.Application.App.Stores.Handlers;

/// <summary>
/// 可用自提档期查询处理器。
/// </summary>
public sealed class GetAvailablePickupSlotsQueryHandler(
    IStoreRepository storeRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<GetAvailablePickupSlotsQuery, IReadOnlyList<StorePickupSlotDto>>
{
    /// <inheritdoc />
    public async Task<IReadOnlyList<StorePickupSlotDto>> Handle(GetAvailablePickupSlotsQuery request, CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var date = request.Date.Date;
        // 1. 读取配置
        var setting = await storeRepository.GetPickupSettingAsync(request.StoreId, tenantId, cancellationToken);
        var allowDays = setting?.AllowDaysAhead ?? 0;
        var allowToday = setting?.AllowToday ?? false;
        var defaultCutoff = setting?.DefaultCutoffMinutes ?? 30;

        // 2. 校验日期范围
        if (!allowToday && date == DateTime.UtcNow.Date)
        {
            return [];
        }

        if (date > DateTime.UtcNow.Date.AddDays(allowDays))
        {
            return [];
        }

        // 3. 读取档期
        var slots = await storeRepository.GetPickupSlotsAsync(request.StoreId, tenantId, cancellationToken);
        var weekday = (int)date.DayOfWeek;
        weekday = weekday == 0 ? 7 : weekday;
        var nowUtc = DateTime.UtcNow;

        // 4. 过滤可用
        var available = slots
            .Where(x => x.IsEnabled && ContainsDay(x.Weekdays, weekday))
            .Select(slot =>
            {
                var cutoff = slot.CutoffMinutes == 0 ? defaultCutoff : slot.CutoffMinutes;
                var slotStartUtc = date.Add(slot.StartTime);
                // 判断截单
                var cutoffTime = slotStartUtc.AddMinutes(-cutoff);
                var isCutoff = nowUtc > cutoffTime;
                var remaining = slot.Capacity - slot.ReservedCount;
                return (slot, isCutoff, remaining);
            })
            .Where(x => !x.isCutoff && x.remaining > 0)
            .Select(x => new StorePickupSlotDto
            {
                Id = x.slot.Id,
                StoreId = x.slot.StoreId,
                Name = x.slot.Name,
                StartTime = x.slot.StartTime,
                EndTime = x.slot.EndTime,
                CutoffMinutes = x.slot.CutoffMinutes,
                Capacity = x.slot.Capacity,
                ReservedCount = x.slot.ReservedCount,
                Weekdays = x.slot.Weekdays,
                IsEnabled = x.slot.IsEnabled
            })
            .ToList();

        return available;
    }

    private static bool ContainsDay(string weekdays, int target)
    {
        // 解析适用星期
        var parts = weekdays.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        return parts.Any(p => int.TryParse(p, out var val) && val == target);
    }
}
