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 SubsidyValidationRule(IDistributorRepository distributorRepository) : IValidationRule { private readonly IDistributorRepository _distributorRepository = distributorRepository; private const string RULE_NAME = "Subsidy and Discount Validation"; private const string AMOUNT_ERROR = "Discount amount doesn't match the expected value"; private const string ELIGIBILITY_ERROR = "Consumer not eligible for applied discount"; private const string CONSUMPTION_ERROR = "Consumption outside eligible range for discount"; private const decimal TOLERANCE = 0.01m; public int Priority => 6; // Run after flag tariff validation public async Task ValidateAsync( BillComplianceRequest request, DistributorInformation distributorInfo, Client clientInfo) { var subsidyInfo = await _distributorRepository.GetSubsidyInformationAsync( request.DistributorName, request.ConsumerGroup, request.Month) ?? throw new InvalidOperationException("Subsidy information not found"); var isValid = true; var message = new StringBuilder(); // Check consumption eligibility if (request.ConsumptionAmount < subsidyInfo.Consumption.MinConsumption || (subsidyInfo.Consumption.MaxConsumption > 0 && request.ConsumptionAmount > subsidyInfo.Consumption.MaxConsumption)) { if (request.DiscountAmount != 0) { isValid = false; message.AppendLine($"{CONSUMPTION_ERROR}. Range: {subsidyInfo.Consumption.MinConsumption}-{subsidyInfo.Consumption.MaxConsumption} kWh"); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } // Get applicable discount rate var discountRate = subsidyInfo.GroupDiscounts.TryGetValue(request.ConsumerGroup.ToLower(), out var specialRate) ? specialRate : subsidyInfo.BaseDiscountPercentage; // Calculate expected discount var expectedDiscount = CalculateDiscount(request, subsidyInfo, discountRate); if (Math.Abs(request.DiscountAmount - expectedDiscount) > TOLERANCE) { isValid = false; message.AppendLine($"{AMOUNT_ERROR}. Expected: {expectedDiscount:F2}, Found: {request.DiscountAmount:F2}"); } return new ValidationResult { IsValid = isValid, RuleName = RULE_NAME, Message = message.ToString().TrimEnd() }; } private static decimal CalculateDiscount( BillComplianceRequest request, SubsidyInformation subsidyInfo, decimal discountRate) { var baseAmount = 0m; if (subsidyInfo.ApplyToTUSD) { baseAmount += request.TUSDAmount; } if (subsidyInfo.ApplyToTE) { baseAmount += request.TEAmount; } if (subsidyInfo.ApplyToFlags) { baseAmount += request.FlagAmount; } return baseAmount * (discountRate / 100m); } } }