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 ICMSValidationRule(IDistributorRepository distributorRepository) : IValidationRule { private readonly IDistributorRepository _distributorRepository = distributorRepository; private const string RULE_NAME = "ICMS Validation"; private const string AMOUNT_ERROR = "ICMS amount doesn't match the expected value"; private const string EXEMPT_ERROR = "ICMS charged to exempt consumer"; private const string BASE_ERROR = "ICMS base calculation is incorrect"; private const decimal TOLERANCE = 0.01m; public int Priority => 6; // Run after public lighting validation public async Task ValidateAsync( BillComplianceRequest request, DistributorInformation distributorInfo, Client clientInfo) { var icmsInfo = await _distributorRepository.GetICMSInformationAsync( request.DistributorName, request.ConsumerGroup, request.Month) ?? throw new InvalidOperationException("ICMS information not found"); var isValid = true; var message = new StringBuilder(); // Check if consumer is exempt from ICMS if (icmsInfo.ExemptGroups.Contains(request.ConsumerGroup.ToLower())) { if (request.ICMSAmount != 0) { isValid = false; message.AppendLine(EXEMPT_ERROR); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } // Get applicable rate var rate = icmsInfo.GroupRates.TryGetValue(request.ConsumerGroup.ToLower(), out var groupRate) ? groupRate : icmsInfo.BaseRate; // Calculate base and expected ICMS var baseAmount = CalculateICMSBase(request, icmsInfo.IncludesTaxInBase); var expectedICMS = CalculateICMSAmount(baseAmount, rate, icmsInfo.IncludesTaxInBase); if (Math.Abs(request.ICMSBase - baseAmount) > TOLERANCE) { isValid = false; message.AppendLine($"{BASE_ERROR}. Expected: {baseAmount:F2}, Found: {request.ICMSBase:F2}"); } if (Math.Abs(request.ICMSAmount - expectedICMS) > TOLERANCE) { isValid = false; message.AppendLine($"{AMOUNT_ERROR}. Expected: {expectedICMS:F2}, Found: {request.ICMSAmount:F2}"); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } private static decimal CalculateICMSBase(BillComplianceRequest request, bool includesTaxInBase) { // Sum all components that are part of ICMS base return request.TUSDAmount + request.TEAmount + request.PowerFactorAdjustment + request.FlagAmount; } private static decimal CalculateICMSAmount(decimal baseAmount, decimal rate, bool includesTaxInBase) { rate /= 100m; // Convert percentage to decimal if (!includesTaxInBase) { // Regular calculation ("por fora") return baseAmount * rate; } // "Por dentro" calculation where ICMS is included in its own base return baseAmount * rate / (1 - rate); } } }