using MediatR;
using TakeoutSaaS.Application.App.Finance.Invoice.Commands;
using TakeoutSaaS.Application.App.Finance.Invoice.Dto;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Finance.Invoice.Handlers;

/// <summary>
/// 保存发票设置处理器。
/// </summary>
public sealed class SaveFinanceInvoiceSettingCommandHandler(
    ITenantInvoiceRepository repository,
    ITenantProvider tenantProvider)
    : IRequestHandler<SaveFinanceInvoiceSettingCommand, FinanceInvoiceSettingDto>
{
    /// <inheritdoc />
    public async Task<FinanceInvoiceSettingDto> Handle(
        SaveFinanceInvoiceSettingCommand request,
        CancellationToken cancellationToken)
    {
        if (!request.EnableElectronicNormalInvoice && !request.EnableElectronicSpecialInvoice)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "至少启用一种发票类型");
        }

        var tenantId = tenantProvider.GetCurrentTenantId();
        var companyName = FinanceInvoiceMapping.NormalizeCompanyName(request.CompanyName);
        var taxpayerNumber = FinanceInvoiceMapping.NormalizeTaxpayerNumber(request.TaxpayerNumber);
        var registeredAddress = FinanceInvoiceMapping.NormalizeOptionalRemark(request.RegisteredAddress, "registeredAddress", 256);
        var registeredPhone = FinanceInvoiceMapping.NormalizeOptionalPhone(request.RegisteredPhone);
        var bankName = FinanceInvoiceMapping.NormalizeOptionalRemark(request.BankName, "bankName", 128);
        var bankAccount = FinanceInvoiceMapping.NormalizeOptionalRemark(request.BankAccount, "bankAccount", 64);
        var autoIssueMaxAmount = FinanceInvoiceMapping.NormalizeAutoIssueMaxAmount(request.AutoIssueMaxAmount);

        var setting = await repository.GetSettingAsync(tenantId, cancellationToken);
        if (setting is null)
        {
            setting = FinanceInvoiceDtoFactory.CreateSettingEntity(
                request,
                companyName,
                taxpayerNumber,
                registeredAddress,
                registeredPhone,
                bankName,
                bankAccount,
                autoIssueMaxAmount);

            await repository.AddSettingAsync(setting, cancellationToken);
        }
        else
        {
            FinanceInvoiceDtoFactory.ApplySettingChanges(
                setting,
                request,
                companyName,
                taxpayerNumber,
                registeredAddress,
                registeredPhone,
                bankName,
                bankAccount,
                autoIssueMaxAmount);

            await repository.UpdateSettingAsync(setting, cancellationToken);
        }

        await repository.SaveChangesAsync(cancellationToken);
        return FinanceInvoiceDtoFactory.ToSettingDto(setting);
    }
}
