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.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Merchants.Handlers;

/// <summary>
/// 创建商户合同。
/// </summary>
public sealed class CreateMerchantContractCommandHandler(
    IMerchantRepository merchantRepository,
    ITenantProvider tenantProvider,
    IIdGenerator idGenerator,
    ICurrentUserAccessor currentUserAccessor)
    : IRequestHandler<CreateMerchantContractCommand, MerchantContractDto>
{
    /// <summary>
    /// 处理创建商户合同请求。
    /// </summary>
    /// <param name="request">创建命令。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>合同 DTO。</returns>
    public async Task<MerchantContractDto> Handle(CreateMerchantContractCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验时间
        if (request.EndDate <= request.StartDate)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "合同结束时间必须晚于开始时间");
        }

        // 2. 查询商户
        var tenantId = tenantProvider.GetCurrentTenantId();
        var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken)
                       ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");

        // 3. 构建合同
        var contract = new MerchantContract
        {
            Id = idGenerator.NextId(),
            MerchantId = merchant.Id,
            ContractNumber = request.ContractNumber.Trim(),
            StartDate = request.StartDate,
            EndDate = request.EndDate,
            FileUrl = request.FileUrl.Trim()
        };

        // 4. 持久化与审计
        await merchantRepository.AddContractAsync(contract, cancellationToken);
        await merchantRepository.AddAuditLogAsync(new MerchantAuditLog
        {
            TenantId = tenantId,
            MerchantId = merchant.Id,
            Action = MerchantAuditAction.ContractUpdated,
            Title = "新增合同",
            Description = $"合同号：{contract.ContractNumber}",
            OperatorId = ResolveOperatorId(),
            OperatorName = ResolveOperatorName()
        }, cancellationToken);

        await merchantRepository.SaveChangesAsync(cancellationToken);

        // 5. 返回 DTO
        return MerchantMapping.ToDto(contract);
    }

    private long? ResolveOperatorId()
    {
        var id = currentUserAccessor.UserId;
        return id == 0 ? null : id;
    }

    private string ResolveOperatorName()
    {
        var id = currentUserAccessor.UserId;
        return id == 0 ? "system" : $"user:{id}";
    }
}
