using System; using System.Data.OleDb; using System.Linq; using System.Threading.Tasks; using Compliance.Domain.Models; using Microsoft.Extensions.Configuration; using System.Net.Http; using System.Data.Common; using System.Collections.Generic; namespace Compliance.Infrastructure.Repositories { public class DistributorRepository : IDistributorRepository { private readonly string _connectionString; private const string BASE_QUERY = "SELECT * FROM [{0}] WHERE Distribuidora = @dist"; private const string GROUP_QUERY = BASE_QUERY + " AND Grupo = @grupo"; private const string MONTH_QUERY = BASE_QUERY + " AND Mes = @mes"; private const string GROUP_MONTH_QUERY = GROUP_QUERY + " AND Mes = @mes"; public DistributorRepository(string connectionString) { _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); } public async Task QuerySingleAsync(string tableName, object parameters) where T : class, new() { using var connection = new OleDbConnection(_connectionString); await connection.OpenAsync(); using var command = CreateCommand(connection, tableName, parameters); using var reader = await command.ExecuteReaderAsync(); return await reader.ReadAsync() ? MapReaderToType(reader) : null; } private static OleDbCommand CreateCommand( OleDbConnection connection, string tableName, object parameters) { var command = connection.CreateCommand(); var query = string.Format(BASE_QUERY, tableName); foreach (var prop in parameters.GetType().GetProperties()) { command.Parameters.AddWithValue($"@{prop.Name.ToLower()}", prop.GetValue(parameters) ?? DBNull.Value); } command.CommandText = query; return command; } private static T MapReaderToType(DbDataReader reader) where T : class, new() { var result = new T(); var properties = typeof(T).GetProperties(); foreach (var prop in properties) { var columnName = prop.Name; var ordinal = reader.GetOrdinal(columnName); if (!reader.IsDBNull(ordinal)) { var value = reader.GetValue(ordinal); prop.SetValue(result, Convert.ChangeType(value, prop.PropertyType)); } } return result; } public async Task GetDistributorInformationAsync(string distributorName, string month) { return await QuerySingleAsync("Distribuidoras", new { dist = distributorName, mes = month }); } public async Task GetTariffInformationAsync(string distributorName, string month) { return await QuerySingleAsync("Tarifas", new { dist = distributorName, mes = month }); } public async Task GetTaxInformationAsync(string distributorName, string month) { return await QuerySingleAsync("Impostos", new { dist = distributorName, mes = month }); } public async Task GetFlagTariffInformationAsync(string distributorName, string month) { return await QuerySingleAsync("BandeiraTarifaria", new { dist = distributorName, mes = month }); } public async Task GetPublicLightingInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("IluminacaoPublica", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetICMSInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("ICMS", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetDemandInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("Demanda", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetReactiveEnergyInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("EnergiaReativa", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetMunicipalTaxInformationAsync( string distributorName, string municipality, string month) { return await QuerySingleAsync("TaxaMunicipal", new { dist = distributorName, municipio = municipality, mes = month }); } public async Task GetSeasonalTariffInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("TarifaSazonal", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetPaymentTermsInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("CondicoesPagamento", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetMinimumBillingAsync(string distributorName) { return await QuerySingleAsync("FaturamentoMinimo", new { dist = distributorName }); } public async Task GetReadingPeriodRulesAsync() { return await QuerySingleAsync("RegrasLeitura", new { }) ?? throw new InvalidOperationException("Reading period rules not found"); } public async Task GetDistributedGenerationInfoAsync(string smartCode) { return await QuerySingleAsync("GeracaoDistribuida", new { codigo = smartCode }) ?? throw new InvalidOperationException("Distributed generation info not found"); } public async Task GetAdditionalChargeInformationAsync( string distributorName, string month) { return await QuerySingleAsync("CobrancasAdicionais", new { dist = distributorName, mes = month }); } public async Task GetSubsidyInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("Subsidios", new { dist = distributorName, grupo = consumerGroup, mes = month }); } public async Task GetMinimumBillingInformationAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("FaturamentoMinimo", new { dist = distributorName, grupo = consumerGroup, mes = month }) ?? throw new InvalidOperationException("Minimum billing information not found"); } public async Task GetMeasurementSystemInfoAsync(string meterNumber) { return await QuerySingleAsync("MeasurementSystems", new { medidor = meterNumber }); } public async Task GetReadingImpedimentInfoAsync( string smartCode, DateTime readingDate) { return await QuerySingleAsync("ReadingImpediments", new { codigo = smartCode, data = readingDate }); } public async Task GetGroupSpecificRulesInfoAsync( string distributorName, string consumerGroup, string month) { return await QuerySingleAsync("RegrasGrupo", new { dist = distributorName, grupo = consumerGroup, mes = month }); } } }