using System.Linq;
using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Stores.Handlers;

/// <summary>
/// 批量生成桌码处理器。
/// </summary>
public sealed class GenerateStoreTablesCommandHandler(
    IStoreRepository storeRepository,
    ITenantProvider tenantProvider,
    ILogger<GenerateStoreTablesCommandHandler> logger)
    : IRequestHandler<GenerateStoreTablesCommand, IReadOnlyList<StoreTableDto>>
{
    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreTableDto>> Handle(GenerateStoreTablesCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验门店存在
        var tenantId = tenantProvider.GetCurrentTenantId();
        var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
        if (store is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
        }

        // 2. 校验区域归属
        if (request.AreaId.HasValue)
        {
            var area = await storeRepository.FindTableAreaByIdAsync(request.AreaId.Value, tenantId, cancellationToken);
            if (area is null || area.StoreId != request.StoreId)
            {
                throw new BusinessException(ErrorCodes.ValidationFailed, "桌台区域不存在或不属于该门店");
            }
        }

        // 3. 校验桌码唯一性
        var existingTables = await storeRepository.GetTablesAsync(request.StoreId, tenantId, cancellationToken);
        var newCodes = Enumerable.Range(request.StartNumber, request.Count)
            .Select(i => $"{request.TableCodePrefix.Trim()}{i}")
            .ToList();
        var conflicts = existingTables.Where(t => newCodes.Contains(t.TableCode, StringComparer.OrdinalIgnoreCase)).ToList();
        if (conflicts.Count > 0)
        {
            throw new BusinessException(ErrorCodes.Conflict, "桌码已存在，生成失败");
        }

        // 4. 构建实体
        var tables = newCodes.Select(code => new StoreTable
        {
            StoreId = request.StoreId,
            AreaId = request.AreaId,
            TableCode = code,
            Capacity = request.DefaultCapacity,
            Tags = request.Tags?.Trim()
        }).ToList();

        // 5. 持久化
        await storeRepository.AddTablesAsync(tables, cancellationToken);
        await storeRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("批量创建桌码 {Count} 条 对应门店 {StoreId}", tables.Count, request.StoreId);

        // 6. 返回 DTO
        return tables.Select(StoreMapping.ToDto).ToList();
    }
}
