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 TariffComponentValidationRule(IDistributorRepository distributorRepository) : IValidationRule { private readonly IDistributorRepository _distributorRepository = distributorRepository; private const string RULE_NAME = "Tariff Component Validation"; private const string TUSD_ERROR = "TUSD amount doesn't match the expected value"; private const string TE_ERROR = "TE amount doesn't match the expected value"; private const string POWER_FACTOR_ERROR = "Power factor adjustment is incorrect"; private const decimal TOLERANCE = 0.01m; private const decimal MIN_POWER_FACTOR = 0.92m; public int Priority => 3; // Run after consumption validation public async Task ValidateAsync( BillComplianceRequest request, DistributorInformation distributorInfo, Client clientInfo) { var tariffInfo = await _distributorRepository.GetTariffInformationAsync( request.DistributorName, request.Month) ?? throw new InvalidOperationException("Tariff information not found"); var isValid = true; var message = new StringBuilder(); // Validate TUSD calculation var expectedTUSD = request.ConsumptionAmount * tariffInfo.TUSDValue; if (Math.Abs(request.TUSDAmount - expectedTUSD) > TOLERANCE) { isValid = false; message.AppendLine(TUSD_ERROR); } // Validate TE calculation var expectedTE = request.ConsumptionAmount * tariffInfo.TEValue; if (Math.Abs(request.TEAmount - expectedTE) > TOLERANCE) { isValid = false; message.AppendLine(TE_ERROR); } // Validate power factor adjustment if applicable if (request.PowerFactor < MIN_POWER_FACTOR) { var powerFactorAdjustment = CalculatePowerFactorAdjustment( request.ConsumptionAmount, request.PowerFactor, tariffInfo); if (Math.Abs(request.PowerFactorAdjustment - powerFactorAdjustment) > TOLERANCE) { isValid = false; message.AppendLine(POWER_FACTOR_ERROR); } } else if (request.PowerFactorAdjustment != 0) { isValid = false; message.AppendLine("Power factor adjustment should be zero when power factor is above minimum"); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } private static decimal CalculatePowerFactorAdjustment( decimal consumption, decimal powerFactor, TariffInformation tariffInfo) { if (powerFactor >= MIN_POWER_FACTOR) return 0; var adjustment = (MIN_POWER_FACTOR / powerFactor - 1) * 100; return consumption * (tariffInfo.TUSDValue + tariffInfo.TEValue) * adjustment / 100; } } }