using System; using System.Threading.Tasks; using System.Text; using Compliance.Domain.Models; using Compliance.DTOs; using Compliance.Infrastructure.Repositories; namespace Compliance.Services.ValidationRules { public class MunicipalTaxValidationRule(IDistributorRepository distributorRepository) : IValidationRule { private readonly IDistributorRepository _distributorRepository = distributorRepository; private const string RULE_NAME = "Municipal Tax Validation"; private const string AMOUNT_ERROR = "Municipal tax amount doesn't match the expected value"; private const string BASE_ERROR = "Municipal tax base calculation is incorrect"; private const string EXEMPT_ERROR = "Municipal tax charged to exempt consumer"; private const decimal TOLERANCE = 0.01m; public int Priority => 7; // Run after ICMS validation public async Task ValidateAsync( BillComplianceRequest request, DistributorInformation distributorInfo, Client clientInfo) { var taxInfo = await _distributorRepository.GetMunicipalTaxInformationAsync( request.DistributorName, request.Municipality, request.Month) ?? throw new InvalidOperationException("Municipal tax information not found"); var isValid = true; var message = new StringBuilder(); // Check if consumer is exempt if (taxInfo.ExemptGroups.Contains(request.ConsumerGroup.ToLower())) { if (request.MunicipalTaxAmount != 0) { isValid = false; message.AppendLine(EXEMPT_ERROR); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } // Get applicable rate var rate = taxInfo.SpecialRates.TryGetValue(request.ConsumerGroup.ToLower(), out var specialRate) ? specialRate : taxInfo.BaseRate; // Calculate base and expected tax var baseAmount = CalculateTaxBase(request, taxInfo); var expectedTax = baseAmount * (rate / 100m); if (Math.Abs(request.MunicipalTaxBase - baseAmount) > TOLERANCE) { isValid = false; message.AppendLine($"{BASE_ERROR}. Expected: {baseAmount:F2}, Found: {request.MunicipalTaxBase:F2}"); } if (Math.Abs(request.MunicipalTaxAmount - expectedTax) > TOLERANCE) { isValid = false; message.AppendLine($"{AMOUNT_ERROR}. Expected: {expectedTax:F2}, Found: {request.MunicipalTaxAmount:F2}"); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } private static decimal CalculateTaxBase(BillComplianceRequest request, MunicipalTaxInformation taxInfo) { var baseAmount = request.TUSDAmount + request.TEAmount + request.PowerFactorAdjustment + request.FlagAmount; if (taxInfo.ApplyToICMS) { baseAmount += request.ICMSAmount; } if (taxInfo.ApplyToPublicLighting) { baseAmount += request.PublicLightingAmount; } return baseAmount; } } }