using MediatR;
using TakeoutSaaS.Application.App.Merchants.Commands;
using TakeoutSaaS.Application.App.Merchants.Dto;
using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Merchants.Enums;
using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;

namespace TakeoutSaaS.Application.App.Merchants.Handlers;

/// <summary>
/// 领取商户审核处理器。
/// </summary>
public sealed class ClaimMerchantReviewHandler(
    IMerchantRepository merchantRepository,
    ICurrentUserAccessor currentUserAccessor)
    : IRequestHandler<ClaimMerchantReviewCommand, ClaimInfoDto>
{
    /// <inheritdoc />
    public async Task<ClaimInfoDto> Handle(ClaimMerchantReviewCommand request, CancellationToken cancellationToken)
    {
        var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");

        if (merchant.Status != MerchantStatus.Pending)
        {
            throw new BusinessException(ErrorCodes.Conflict, "商户不在待审核状态");
        }

        var now = DateTime.UtcNow;
        if (merchant.ClaimedBy.HasValue && merchant.ClaimExpiresAt.HasValue && merchant.ClaimExpiresAt > now)
        {
            if (merchant.ClaimedBy != currentUserAccessor.UserId)
            {
                throw new BusinessException(ErrorCodes.Conflict, $"该审核已被 {merchant.ClaimedByName} 领取");
            }

            return ToDto(merchant);
        }

        var actorName = currentUserAccessor.IsAuthenticated
            ? $"user:{currentUserAccessor.UserId}"
            : "system";

        merchant.ClaimedBy = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId;
        merchant.ClaimedByName = actorName;
        merchant.ClaimedAt = now;
        merchant.ClaimExpiresAt = now.AddMinutes(30);

        await merchantRepository.UpdateMerchantAsync(merchant, cancellationToken);
        await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
        {
            TenantId = merchant.TenantId,
            MerchantId = merchant.Id,
            Action = MerchantAuditAction.ReviewClaimed,
            Title = "领取审核",
            Description = $"领取人：{actorName}",
            OperatorId = currentUserAccessor.UserId == 0 ? null : currentUserAccessor.UserId,
            OperatorName = actorName
        }, cancellationToken);
        await merchantRepository.SaveChangesAsync(cancellationToken);

        return ToDto(merchant);
    }

    private static ClaimInfoDto ToDto(Domain.Merchants.Entities.Merchant merchant)
        => new()
        {
            MerchantId = merchant.Id,
            ClaimedBy = merchant.ClaimedBy,
            ClaimedByName = merchant.ClaimedByName,
            ClaimedAt = merchant.ClaimedAt,
            ClaimExpiresAt = merchant.ClaimExpiresAt
        };
}
