using Microsoft.Extensions.Options; using OpenCand.API.Config; using OpenCand.API.Model; using OpenCand.API.Repository; using OpenCand.Core.Models; using OpenCand.Repository; namespace OpenCand.API.Services { public class OpenCandService { private readonly OpenCandRepository openCandRepository; private readonly CandidatoRepository candidatoRepository; private readonly BemCandidatoRepository bemCandidatoRepository; private readonly DespesaReceitaRepository despesaReceitaRepository; private readonly IConfiguration configuration; private readonly FotosSettings fotoSettings; private readonly ILogger logger; public OpenCandService( OpenCandRepository openCandRepository, CandidatoRepository candidatoRepository, BemCandidatoRepository bemCandidatoRepository, DespesaReceitaRepository despesaReceitaRepository, IOptions fotoSettings, IConfiguration configuration, ILogger logger) { this.openCandRepository = openCandRepository; this.candidatoRepository = candidatoRepository; this.bemCandidatoRepository = bemCandidatoRepository; this.despesaReceitaRepository = despesaReceitaRepository; this.fotoSettings = fotoSettings.Value; this.configuration = configuration; this.logger = logger; } public async Task GetOpenCandStatsAsync() { logger.LogInformation("Getting OpenCand stats"); return await openCandRepository.GetOpenCandStatsAsync(); } public async Task GetDataAvailabilityStatsAsync() { logger.LogInformation("Getting data availability stats"); var stats = await openCandRepository.GetDataAvailabilityAsync(); return stats; } public async Task GetDatabaseTechStatsAsync() { logger.LogInformation("Getting database tech stats"); var stats = await openCandRepository.GetDatabaseTechStatsAsync(); stats.Tables = stats.Tables.OrderBy(t => t.Name).ToList(); stats.MaterializedViews = stats.MaterializedViews.OrderBy(mv => mv.Name).ToList(); return stats; } public async Task SearchCandidatosAsync(string query) { logger.LogInformation($"Searching candidatos with query: {query}"); return new CandidatoSearchResult() { Candidatos = await candidatoRepository.SearchCandidatosAsync(query) ?? new List() }; } public async Task GetRandomCandidato() { logger.LogInformation("Getting random candidato"); return await candidatoRepository.GetRandomCandidatoIdAsync(); } public async Task GetCandidatoAsync(Guid idcandidato) { var result = await candidatoRepository.GetCandidatoAsync(idcandidato); var eleicoes = await candidatoRepository.GetCandidatoMappingById(idcandidato); var candidatoExt = await candidatoRepository.GetCandidatoExtById(idcandidato); try { await candidatoRepository.IncreaseCandidatoPopularity(idcandidato); } catch (Exception ex) { logger.LogError(ex, $"Error increasing popularity for Candidato ID {idcandidato}"); } if (result == null) { throw new KeyNotFoundException($"Candidato with ID {idcandidato} not found."); } if (eleicoes == null || eleicoes.Count == 0) { throw new KeyNotFoundException($"CandidatoMapping for ID {idcandidato} not found."); } if (candidatoExt == null) { throw new KeyNotFoundException($"CandidatoExt for ID {idcandidato} not found."); } foreach (var eleicao in eleicoes) { eleicao.Partido = await candidatoRepository.GetPartidoBySigla(eleicao.Sgpartido); } var lastEleicao = eleicoes.OrderByDescending(e => e.Ano).First(); result.FotoUrl = $"{fotoSettings.ApiBasePath}/foto_cand{lastEleicao.Ano}_{lastEleicao.SiglaUF}_div/F{lastEleicao.SiglaUF}{lastEleicao.SqCandidato}_div.jpg"; result.Eleicoes = eleicoes.OrderByDescending(e => e.Ano).ToList(); result.CandidatoExt = candidatoExt.OrderByDescending(ce => ce.Ano).ToList(); logger.LogDebug($"Found Candidato: {result.Nome}, ID: {result.IdCandidato}, CPF: {result.Cpf}, FotoUrl: {result.FotoUrl}"); return result; } public async Task GetBemCandidatoById(Guid idcandidato) { var result = await bemCandidatoRepository.GetBemCandidatoAsync(idcandidato); if (result == null) { result = new List(); } logger.LogInformation($"Found {result.Count} bens for Candidato ID {idcandidato}"); return new BemCandidatoResult() { Bens = result.OrderByDescending(r => r.TipoBem).ThenByDescending(r => r.Valor).ToList() }; } public async Task GetCandidatoRedeSocialById(Guid idcandidato) { logger.LogInformation($"Getting redes sociais for Candidato ID {idcandidato}"); var result = await candidatoRepository.GetCandidatoRedeSocialById(idcandidato); if (result == null) { result = new List(); } logger.LogDebug($"Found {result.Count} redes sociais for Candidato ID {idcandidato}"); return new RedeSocialResult() { RedesSociais = result.OrderByDescending(r => r.Ano).ToList() }; } public async Task GetCandidatoCpfById(Guid idcandidato) { logger.LogInformation($"Getting CPF for Candidato ID {idcandidato}"); var result = await candidatoRepository.GetCandidatoCpfAsync(idcandidato); if (result == null) { return new CpfRevealResult(); } logger.LogDebug($"Found CPF {result} for Candidato ID {idcandidato}"); return new CpfRevealResult() { Cpf = result }; } public async Task GetDespesasByIdAndYear(Guid idcandidato) { logger.LogInformation($"Getting despesas for Candidato ID {idcandidato}"); var result = await despesaReceitaRepository.GetDespesasByCandidatoIdYearAsync(idcandidato); if (result == null) { return new DespesasResult(); } logger.LogDebug($"Found {result.Count} despesas for Candidato ID {idcandidato}"); return new DespesasResult() { Despesas = result.OrderByDescending(d => d.Ano).ThenByDescending(d => d.Valor).ToList() }; } public async Task GetReceitasByIdAndYear(Guid idcandidato) { logger.LogInformation($"Getting receitas for Candidato ID {idcandidato}"); var result = await despesaReceitaRepository.GetReceitasByCandidatoIdYearAsync(idcandidato); if (result == null) { return new ReceitaResult(); } logger.LogDebug($"Found {result.Count} receitas for Candidato ID {idcandidato}"); return new ReceitaResult() { Receitas = result.OrderByDescending(d => d.Ano).ThenByDescending(d => d.Valor).ToList() }; } } }