2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//Elecciones.Worker/LowPriorityDataWorker.cs  
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Database ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Database.Entities ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Infrastructure.Services ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Microsoft.EntityFrameworkCore ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								namespace  Elecciones.Worker ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								public  class  LowPriorityDataWorker  :  BackgroundService  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  const  int  EleccionId  =  2 ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  private  readonly  ILogger < LowPriorityDataWorker >  _logger ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  SharedTokenService  _tokenService ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  IServiceProvider  _serviceProvider ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  IElectoralApiService  _apiService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  readonly  WorkerConfigService  _configService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // Una variable para rastrear la tarea de telegramas, si está en ejecución. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  Task ?  _telegramasTask ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  public  LowPriorityDataWorker ( 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  ILogger < LowPriorityDataWorker >  logger , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  SharedTokenService  tokenService , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  IServiceProvider  serviceProvider , 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  IElectoralApiService  apiService , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  WorkerConfigService  configService ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _logger  =  logger ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _tokenService  =  tokenService ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _serviceProvider  =  serviceProvider ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _apiService  =  apiService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    _configService  =  configService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  protected  override  async  Task  ExecuteAsync ( CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _logger . LogInformation ( "Worker de Baja Prioridad iniciado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // La sincronización inicial sigue siendo un paso de bloqueo, es necesario. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    await  SincronizarCatalogosMaestrosAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  ( ! stoppingToken . IsCancellationRequested ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "--- Iniciando Ciclo de Datos de Baja Prioridad ---" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  authToken  =  await  _tokenService . GetValidAuthTokenAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( string . IsNullOrEmpty ( authToken ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogError ( "Ciclo de Baja Prioridad: No se pudo obtener token. Reintentando en 1 minuto." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  Task . Delay ( TimeSpan . FromMinutes ( 1 ) ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  settings  =  await  _configService . GetSettingsAsync ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( settings . Prioridad  = =  "Telegramas"  & &  settings . ResultadosActivado ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Ejecutando tareas de Resultados en baja prioridad." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        await  SondearEstadoRecuentoGeneralAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        await  SondearResultadosMunicipalesAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearResumenProvincialAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else  if  ( settings . Prioridad  = =  "Resultados"  & &  settings . BajasActivado ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Ejecutando tareas de Baja Prioridad en baja prioridad." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearProyeccionBancasAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 10:12:12 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        //await SondearNuevosTelegramasAsync(authToken, stoppingToken); 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Worker de baja prioridad inactivo según la configuración." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:29:50 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  Task . Delay ( TimeSpan . FromMinutes ( 5 ) ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      catch  ( TaskCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  async  Task  SondearResultadosMunicipalesAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  municipiosASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  30  & &  a . DistritoId  ! =  null  & &  a . SeccionId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  todasLasCategorias  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! municipiosASondear . Any ( )  | |  ! todasLasCategorias . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron Partidos (NivelId 30) o Categorías para sondear resultados." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de resultados para {m} municipios y {c} categorías..." ,  municipiosASondear . Count ,  todasLasCategorias . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  municipio  in  municipiosASondear ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        var  tareasCategoria  =  todasLasCategorias . Select ( async  categoria  = > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  resultados  =  await  _apiService . GetResultadosAsync ( authToken ,  municipio . DistritoId ! ,  municipio . SeccionId ! ,  null ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( resultados  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            using  var  innerScope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  innerDbContext  =  innerScope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // --- LLAMADA CORRECTA --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  GuardarResultadosDeAmbitoAsync ( innerDbContext ,  municipio . Id ,  categoria . Id ,  resultados ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  Task . WhenAll ( tareasCategoria ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error inesperado durante el sondeo de resultados municipales." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  GuardarResultadosDeAmbitoAsync ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      EleccionesDbContext  dbContext ,  int  ambitoId ,  int  categoriaId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      Elecciones . Core . DTOs . ResultadosDto  resultadosDto ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    var  estadoRecuento  =  await  dbContext . EstadosRecuentos . FindAsync ( new  object [ ]  {  ambitoId ,  categoriaId  } ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( estadoRecuento  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      estadoRecuento  =  new  EstadoRecuento  {  EleccionId  =  EleccionId ,  AmbitoGeograficoId  =  ambitoId ,  CategoriaId  =  categoriaId  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      dbContext . EstadosRecuentos . Add ( estadoRecuento ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . FechaTotalizacion  =  DateTime . Parse ( resultadosDto . FechaTotalizacion ) . ToUniversalTime ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasEsperadas  =  resultadosDto . EstadoRecuento . MesasEsperadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasTotalizadas  =  resultadosDto . EstadoRecuento . MesasTotalizadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasTotalizadasPorcentaje  =  resultadosDto . EstadoRecuento . MesasTotalizadasPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . CantidadElectores  =  resultadosDto . EstadoRecuento . CantidadElectores ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . CantidadVotantes  =  resultadosDto . EstadoRecuento . CantidadVotantes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . ParticipacionPorcentaje  =  resultadosDto . EstadoRecuento . ParticipacionPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( resultadosDto . ValoresTotalizadosOtros  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosEnBlanco  =  resultadosDto . ValoresTotalizadosOtros . VotosEnBlanco ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosEnBlancoPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosEnBlancoPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosNulos  =  resultadosDto . ValoresTotalizadosOtros . VotosNulos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosNulosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosNulosPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosRecurridos  =  resultadosDto . ValoresTotalizadosOtros . VotosRecurridos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosRecurridosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosRecurridosPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-15 11:44:22 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      estadoRecuento . VotosComando  =  resultadosDto . ValoresTotalizadosOtros . VotosComando ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosComandoPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosComandoPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosImpugnados  =  resultadosDto . ValoresTotalizadosOtros . VotosImpugnados ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosImpugnadosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosImpugnadosPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    foreach  ( var  votoPositivoDto  in  resultadosDto . ValoresTotalizadosPositivos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:34:12 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // PASO 1: VERIFICAR SI LA AGRUPACIÓN YA EXISTE EN NUESTRA BD 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  agrupacion  =  await  dbContext . AgrupacionesPoliticas . FindAsync ( votoPositivoDto . IdAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 2: SI NO EXISTE, LA CREAMOS "SOBRE LA MARCHA" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( agrupacion  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "Agrupación con ID {AgrupacionId} ('{Nombre}') no encontrada en el catálogo local. Creándola desde los datos de resultados." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            votoPositivoDto . IdAgrupacion ,  votoPositivoDto . NombreAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        agrupacion  =  new  AgrupacionPolitica 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          Id  =  votoPositivoDto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          Nombre  =  votoPositivoDto . NombreAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // El IdTelegrama puede ser nulo, usamos el operador '??' para asignar un string vacío si es así. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          IdTelegrama  =  votoPositivoDto . IdAgrupacionTelegrama  ? ?  string . Empty 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . AgrupacionesPoliticas . AddAsync ( agrupacion ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // No es necesario llamar a SaveChangesAsync aquí, se hará al final. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 3: CONTINUAR CON LA LÓGICA DE GUARDADO DEL VOTO 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  resultadoVoto  =  await  dbContext . ResultadosVotos . FirstOrDefaultAsync ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          rv  = >  rv . AmbitoGeograficoId  = =  ambitoId  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                rv . CategoriaId  = =  categoriaId  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                rv . AgrupacionPoliticaId  = =  votoPositivoDto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          stoppingToken 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( resultadoVoto  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        resultadoVoto  =  new  ResultadoVoto 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          EleccionId  =  EleccionId , 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          AmbitoGeograficoId  =  ambitoId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          CategoriaId  =  categoriaId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          AgrupacionPoliticaId  =  votoPositivoDto . IdAgrupacion 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dbContext . ResultadosVotos . Add ( resultadoVoto ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      resultadoVoto . CantidadVotos  =  votoPositivoDto . Votos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      resultadoVoto . PorcentajeVotos  =  votoPositivoDto . VotosPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( DbUpdateException  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "DbUpdateException al guardar resultados para AmbitoId {ambitoId} y CategoriaId {categoriaId}" ,  ambitoId ,  categoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// Obtiene y actualiza el resumen de votos y el estado del recuento a nivel provincial para CADA categoría. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Este método itera sobre todas las provincias y categorías, obteniendo sus resultados consolidados 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// y guardándolos en las tablas 'ResumenesVotos' y 'EstadosRecuentosGenerales'. 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearResumenProvincialAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Resúmenes Provinciales..." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  provinciasASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  10  & &  a . DistritoId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  todasLasCategorias  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( ! provinciasASondear . Any ( )  | |  ! todasLasCategorias . Any ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron Provincias o Categorías para sondear resúmenes." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      foreach  ( var  provincia  in  provinciasASondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  todasLasCategorias ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          // Usamos GetResultados sin seccionId/municipioId para obtener el resumen del distrito. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  resultadosDto  =  await  _apiService . GetResultadosAsync ( authToken ,  provincia . DistritoId ! ,  null ,  null ,  categoria . Id ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( resultadosDto ? . ValoresTotalizadosPositivos  is  {  Count :  >  0  }  nuevosVotos ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // Usamos una transacción para asegurar que el borrado y la inserción sean atómicos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  using  var  transaction  =  await  dbContext . Database . BeginTransactionAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // A. Borrar los resúmenes viejos SOLO para esta provincia y categoría. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  dbContext . ResumenesVotos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . Where ( rv  = >  rv . AmbitoGeograficoId  = =  provincia . Id  & &  rv . CategoriaId  = =  categoria . Id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . ExecuteDeleteAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // B. Añadir los nuevos resúmenes. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            foreach  ( var  voto  in  nuevosVotos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              dbContext . ResumenesVotos . Add ( new  ResumenVoto 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                EleccionId  =  EleccionId , 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                AmbitoGeograficoId  =  provincia . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                CategoriaId  =  categoria . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                AgrupacionPoliticaId  =  voto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                Votos  =  voto . Votos , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                VotosPorcentaje  =  voto . VotosPorcentaje 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // C. Guardar los cambios en la tabla ResumenesVotos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // No es necesario actualizar EstadosRecuentosGenerales aquí, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // ya que el método SondearEstadoRecuentoGeneralAsync se encarga de eso 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // de forma más específica y eficiente. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  transaction . CommitAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        }  // Fin bucle categorías 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  // Fin bucle provincias 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Resúmenes Provinciales completado." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de resúmenes provinciales cancelado." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Resúmenes Provinciales." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Obtiene y actualiza el estado general del recuento a nivel provincial para CADA categoría electoral. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Esta versión es robusta: consulta dinámicamente las categorías, usa la clave primaria compuesta 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// de la base de datos y guarda todos los cambios en una única transacción al final. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="authToken">El token de autenticación válido para la sesión.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="stoppingToken">El token de cancelación para detener la operación.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearEstadoRecuentoGeneralAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  provinciasASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  10  & &  a . DistritoId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Busca NivelId 1 (País) o 0 como fallback. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  ambitoNacional  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . FirstOrDefaultAsync ( a  = >  a . NivelId  = =  1  | |  a . NivelId  = =  0 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasParaSondear  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( ! provinciasASondear . Any ( )  | |  ! categoriasParaSondear . Any ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron Provincias o Categorías para sondear estado general." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Estado Recuento General para {provCount} provincias, el total nacional y {catCount} categorías..." ,  provinciasASondear . Count ,  categoriasParaSondear . Count ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Sondeo a nivel provincial 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  provincia  in  provinciasASondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categoriasParaSondear ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          var  estadoDto  =  await  _apiService . GetEstadoRecuentoGeneralAsync ( authToken ,  provincia . DistritoId ! ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( estadoDto  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  registroDb  =  await  dbContext . EstadosRecuentosGenerales . FindAsync ( new  object [ ]  {  provincia . Id ,  categoria . Id  } ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( registroDb  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              registroDb  =  new  EstadoRecuentoGeneral  {  EleccionId  =  EleccionId ,  AmbitoGeograficoId  =  provincia . Id ,  CategoriaId  =  categoria . Id  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              dbContext . EstadosRecuentosGenerales . Add ( registroDb ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . FechaTotalizacion  =  DateTime . UtcNow ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . MesasEsperadas  =  estadoDto . MesasEsperadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . MesasTotalizadas  =  estadoDto . MesasTotalizadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . MesasTotalizadasPorcentaje  =  estadoDto . MesasTotalizadasPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . CantidadElectores  =  estadoDto . CantidadElectores ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . CantidadVotantes  =  estadoDto . CantidadVotantes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb . ParticipacionPorcentaje  =  estadoDto . ParticipacionPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Bloque para el sondeo a nivel nacional 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ambitoNacional  ! =  null  & &  ! stoppingToken . IsCancellationRequested ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Sondeando totales a nivel Nacional (Ambito ID: {ambitoId})..." ,  ambitoNacional . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categoriasParaSondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  estadoNacionalDto  =  await  _apiService . GetEstadoRecuentoGeneralAsync ( authToken ,  "" ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( estadoNacionalDto  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            var  registroNacionalDb  =  await  dbContext . EstadosRecuentosGenerales . FindAsync ( new  object [ ]  {  ambitoNacional . Id ,  categoria . Id  } ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( registroNacionalDb  = =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              registroNacionalDb  =  new  EstadoRecuentoGeneral  {  EleccionId  =  EleccionId ,  AmbitoGeograficoId  =  ambitoNacional . Id ,  CategoriaId  =  categoria . Id  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              dbContext . EstadosRecuentosGenerales . Add ( registroNacionalDb ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . FechaTotalizacion  =  DateTime . UtcNow ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . MesasEsperadas  =  estadoNacionalDto . MesasEsperadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . MesasTotalizadas  =  estadoNacionalDto . MesasTotalizadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . MesasTotalizadasPorcentaje  =  estadoNacionalDto . MesasTotalizadasPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . CantidadElectores  =  estadoNacionalDto . CantidadElectores ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . CantidadVotantes  =  estadoNacionalDto . CantidadVotantes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroNacionalDb . ParticipacionPorcentaje  =  estadoNacionalDto . ParticipacionPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _logger . LogInformation ( "Datos nacionales para categoría '{catNombre}' actualizados." ,  categoria . Nombre ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      else  if  ( ambitoNacional  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontró el ámbito geográfico para el Nivel Nacional (NivelId 1 o 0). No se pueden capturar los totales del país." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 15:49:15 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Guardar todos los cambios 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( dbContext . ChangeTracker . HasChanges ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Sondeo de Estado Recuento General completado. Se han guardado los cambios en la base de datos." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Sondeo de Estado Recuento General completado. No se detectaron cambios." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Estado Recuento General cancelado." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Estado Recuento General." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Descarga y sincroniza los catálogos base (Categorías, Ámbitos, Agrupaciones) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// desde la API a la base de datos local. Se ejecuta una sola vez al iniciar el worker. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Utiliza una estrategia de guardado en lotes para manejar grandes volúmenes de datos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// sin sobrecargar la base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="stoppingToken">El token de cancelación para detener la operación.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SincronizarCatalogosMaestrosAsync ( CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sincronización de catálogos maestros..." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // --- CORRECCIÓN: Usar el _tokenService inyectado --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  authToken  =  await  _tokenService . GetValidAuthTokenAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( string . IsNullOrEmpty ( authToken )  | |  stoppingToken . IsCancellationRequested ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogError ( "No se pudo obtener token para la sincronización de catálogos. La operación se cancela." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Creamos un scope de servicios para obtener una instancia fresca de DbContext. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 2: Sincronizar las categorías electorales. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Es un catálogo pequeño y es la base para las siguientes consultas. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasApi  =  await  _apiService . GetCategoriasAsync ( authToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( categoriasApi  is  null  | |  ! categoriasApi . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "La API no devolvió datos para el catálogo de Categorías. La sincronización no puede continuar." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  distinctCategorias  =  categoriasApi . GroupBy ( c  = >  c . CategoriaId ) . Select ( g  = >  g . First ( ) ) . OrderBy ( c  = >  c . Orden ) . ToList ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Se procesarán {count} categorías electorales." ,  distinctCategorias . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasEnDb  =  await  dbContext . CategoriasElectorales . ToDictionaryAsync ( c  = >  c . Id ,  c  = >  c ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  categoriaDto  in  distinctCategorias ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! categoriasEnDb . ContainsKey ( categoriaDto . CategoriaId ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          dbContext . CategoriasElectorales . Add ( new  CategoriaElectoral  {  Id  =  categoriaDto . CategoriaId ,  Nombre  =  categoriaDto . Nombre ,  Orden  =  categoriaDto . Orden  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Guardamos las categorías primero para asegurar su existencia. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 3: Cargar los catálogos existentes en memoria para una comparación eficiente. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Esto evita hacer miles de consultas a la BD dentro de un bucle. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Para los ámbitos, creamos una clave única robusta que funciona incluso con campos nulos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  ambitosEnDb  =  new  Dictionary < string ,  AmbitoGeografico > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  todosLosAmbitos  =  await  dbContext . AmbitosGeograficos . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  ambito  in  todosLosAmbitos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        string  clave  =  $"{ambito.NivelId}|{ambito.DistritoId}|{ambito.SeccionProvincialId}|{ambito.SeccionId}|{ambito.MunicipioId}|{ambito.CircuitoId}|{ambito.EstablecimientoId}|{ambito.MesaId}" ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! ambitosEnDb . ContainsKey ( clave ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ambitosEnDb . Add ( clave ,  ambito ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  agrupacionesEnDb  =  await  dbContext . AgrupacionesPoliticas . ToDictionaryAsync ( a  = >  a . Id ,  a  = >  a ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Variable para llevar la cuenta del total de registros insertados. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int  totalCambiosGuardados  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 4: Iterar sobre cada categoría para sincronizar sus ámbitos y agrupaciones. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  categoria  in  distinctCategorias ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "--- Sincronizando datos para la categoría: {Nombre} (ID: {Id}) ---" ,  categoria . Nombre ,  categoria . CategoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        var  catalogoDto  =  await  _apiService . GetCatalogoAmbitosAsync ( authToken ,  categoria . CategoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( catalogoDto  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // 4.1 - Procesar y añadir ÁMBITOS nuevos al DbContext 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          foreach  ( var  ambitoDto  in  catalogoDto . Ambitos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            string  claveUnica  =  $"{ambitoDto.NivelId}|{ambitoDto.CodigoAmbitos.DistritoId}|{ambitoDto.CodigoAmbitos.SeccionProvincialId}|{ambitoDto.CodigoAmbitos.SeccionId}|{ambitoDto.CodigoAmbitos.MunicipioId}|{ambitoDto.CodigoAmbitos.CircuitoId}|{ambitoDto.CodigoAmbitos.EstablecimientoId}|{ambitoDto.CodigoAmbitos.MesaId}" ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( ! ambitosEnDb . ContainsKey ( claveUnica ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 11:18:48 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              string  nombreCorregido  =  ambitoDto . Nombre ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              // VERIFICAMOS SI ES UNA COMUNA DE CABA 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              // Condición: El DistritoId es "01" (CABA) Y el NivelId corresponde a Departamento/Comuna (30) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              // Y el nombre es simplemente un número. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              if  ( ambitoDto . CodigoAmbitos . DistritoId  = =  "01"  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  ambitoDto . NivelId  = =  30  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  int . TryParse ( ambitoDto . Nombre ,  out  int  numeroComuna ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                // Si cumple las condiciones, le damos el formato correcto. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                nombreCorregido  =  $"COMUNA {numeroComuna}" ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogInformation ( "Nombre de comuna de CABA corregido: de '{Original}' a '{Corregido}'" ,  ambitoDto . Nombre ,  nombreCorregido ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								              var  nuevoAmbito  =  new  AmbitoGeografico 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 11:18:48 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                // Usamos el nombre corregido en lugar del original. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                Nombre  =  nombreCorregido , 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                NivelId  =  ambitoDto . NivelId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                DistritoId  =  ambitoDto . CodigoAmbitos . DistritoId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                SeccionProvincialId  =  ambitoDto . CodigoAmbitos . SeccionProvincialId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                SeccionId  =  ambitoDto . CodigoAmbitos . SeccionId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MunicipioId  =  ambitoDto . CodigoAmbitos . MunicipioId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                CircuitoId  =  ambitoDto . CodigoAmbitos . CircuitoId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                EstablecimientoId  =  ambitoDto . CodigoAmbitos . EstablecimientoId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MesaId  =  ambitoDto . CodigoAmbitos . MesaId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              dbContext . AmbitosGeograficos . Add ( nuevoAmbito ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              ambitosEnDb . Add ( claveUnica ,  nuevoAmbito ) ;  // Añadir también al diccionario en memoria 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // 4.2 - Procesar y añadir AGRUPACIONES nuevas al DbContext 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  provincia  =  catalogoDto . Ambitos . FirstOrDefault ( a  = >  a . NivelId  = =  10 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( provincia  ! =  null  & &  ! string . IsNullOrEmpty ( provincia . CodigoAmbitos . DistritoId ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Usamos un try-catch porque no todas las categorías tienen agrupaciones a nivel provincial. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              var  agrupacionesApi  =  await  _apiService . GetAgrupacionesAsync ( authToken ,  provincia . CodigoAmbitos . DistritoId ,  categoria . CategoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              if  ( agrupacionesApi  ! =  null  & &  agrupacionesApi . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                foreach  ( var  agrupacionDto  in  agrupacionesApi ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  if  ( ! agrupacionesEnDb . ContainsKey ( agrupacionDto . IdAgrupacion ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    var  nuevaAgrupacion  =  new  AgrupacionPolitica 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      Id  =  agrupacionDto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      IdTelegrama  =  agrupacionDto . IdAgrupacionTelegrama , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      Nombre  =  agrupacionDto . NombreAgrupacion 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    dbContext . AgrupacionesPoliticas . Add ( nuevaAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    agrupacionesEnDb . Add ( nuevaAgrupacion . Id ,  nuevaAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              _logger . LogWarning ( ex ,  "No se pudieron obtener agrupaciones para la categoría '{catNombre}' ({catId})." ,  categoria . Nombre ,  categoria . CategoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Después de procesar todos los ámbitos y agrupaciones de UNA categoría, guardamos los cambios. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Esto divide la inserción masiva de ~50,000 registros en 3 transacciones más pequeñas, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // evitando timeouts y fallos en la base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( dbContext . ChangeTracker . HasChanges ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          int  cambiosEnLote  =  await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          totalCambiosGuardados  + =  cambiosEnLote ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          _logger . LogInformation ( "Guardados {count} registros de catálogo para la categoría '{catNombre}'." ,  cambiosEnLote ,  categoria . Nombre ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Ya no hay un SaveChangesAsync() gigante aquí. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "{count} nuevos registros de catálogo han sido guardados en total." ,  totalCambiosGuardados ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sincronización de catálogos maestros finalizada." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO durante la sincronización de catálogos." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:54:57 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// Esta versión es completamente robusta: maneja respuestas de API vacías o con fechas mal formadas, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// guarda la CategoriaId y usa una transacción atómica para la escritura en base de datos. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:27:27 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="authToken">El token de autenticación válido para la sesión.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="stoppingToken">El token de cancelación para detener la operación.</param> 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearProyeccionBancasAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasDeBancas  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( c  = >  c . Nombre . Contains ( "SENADORES" )  | |  c . Nombre . Contains ( "DIPUTADOS" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // --- MODIFICACIÓN 1: Obtener todos los ámbitos en una sola consulta --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  ambitosASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . Where ( a  = >  ( a . NivelId  = =  10  | |  a . NivelId  = =  20 )  & &  a . DistritoId  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  provincia  =  ambitosASondear . FirstOrDefault ( a  = >  a . NivelId  = =  10 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  seccionesElectorales  =  ambitosASondear . Where ( a  = >  a . NivelId  = =  20 ) . ToList ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      if  ( ! categoriasDeBancas . Any ( )  | |  provincia  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:51:26 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron categorías de bancas o el ámbito provincial en la BD. Omitiendo sondeo de bancas." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Bancas a nivel Provincial y para {count} Secciones Electorales..." ,  seccionesElectorales . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:38:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  todasLasProyecciones  =  new  List < ProyeccionBanca > ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:51:26 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      bool  hasReceivedAnyNewData  =  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // --- MODIFICACIÓN 2: Usar un diccionario para no buscar repetidamente en la BD --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  agrupacionesEnDb  =  await  dbContext . AgrupacionesPoliticas . ToDictionaryAsync ( a  = >  a . Id ,  a  = >  a ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // Bucle combinado para todos los ámbitos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  ambito  in  ambitosASondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categoriasDeBancas ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Llamada a la API (lógica adaptada para ambos niveles) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  repartoBancasDto  =  await  _apiService . GetBancasAsync ( authToken ,  ambito . DistritoId ! ,  ambito . SeccionProvincialId ,  categoria . Id ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:54:57 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( repartoBancasDto ? . RepartoBancas  is  {  Count :  >  0  }  bancas ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:38:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            hasReceivedAnyNewData  =  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:54:57 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            DateTime  fechaTotalizacion ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( ! DateTime . TryParse ( repartoBancasDto . FechaTotalizacion ,  out  var  parsedDate ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              _logger . LogWarning ( "No se pudo parsear FechaTotalizacion ('{dateString}') para bancas. Usando la hora actual." ,  repartoBancasDto . FechaTotalizacion ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:54:57 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              fechaTotalizacion  =  DateTime . UtcNow ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              fechaTotalizacion  =  parsedDate . ToUniversalTime ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:27:27 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            foreach  ( var  banca  in  bancas ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              // --- MODIFICACIÓN 3: Lógica de "Upsert" para Agrupaciones --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              if  ( ! agrupacionesEnDb . ContainsKey ( banca . IdAgrupacion ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogWarning ( "Agrupación con ID {AgrupacionId} ('{Nombre}') no encontrada. Creándola desde los datos de bancas." ,  banca . IdAgrupacion ,  banca . NombreAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                var  nuevaAgrupacion  =  new  AgrupacionPolitica 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  Id  =  banca . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  Nombre  =  banca . NombreAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  IdTelegrama  =  banca . IdAgrupacionTelegrama  ? ?  string . Empty 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                await  dbContext . AgrupacionesPoliticas . AddAsync ( nuevaAgrupacion ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                agrupacionesEnDb . Add ( nuevaAgrupacion . Id ,  nuevaAgrupacion ) ;  // Añadir al diccionario para no volver a crearla 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:38:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              todasLasProyecciones . Add ( new  ProyeccionBanca 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                EleccionId  =  EleccionId , 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                AmbitoGeograficoId  =  ambito . Id , 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                AgrupacionPoliticaId  =  banca . IdAgrupacion , 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:27:27 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                NroBancas  =  banca . NroBancas , 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 12:54:57 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                CategoriaId  =  categoria . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                FechaTotalizacion  =  fechaTotalizacion 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								              } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:38:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( hasReceivedAnyNewData ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:51:26 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Se recibieron datos válidos de bancas. Procediendo a actualizar la base de datos..." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        await  using  var  transaction  =  await  dbContext . Database . BeginTransactionAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Si se crearon nuevas agrupaciones, se guardarán aquí primero. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Luego, procedemos con las proyecciones. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        await  dbContext . Database . ExecuteSqlRawAsync ( "DELETE FROM ProyeccionesBancas" ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:38:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        await  dbContext . ProyeccionesBancas . AddRangeAsync ( todasLasProyecciones ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  transaction . CommitAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:51:26 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogInformation ( "La tabla de proyecciones ha sido actualizada con {count} registros." ,  todasLasProyecciones . Count ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-17 12:13:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Sondeo de Bancas completado. No se encontraron datos nuevos, la tabla no fue modificada." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 17:51:26 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de bancas cancelado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Bancas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Busca y descarga nuevos telegramas de forma masiva y concurrente. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Este método crea una lista de todas las combinaciones de Partido/Categoría, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// las consulta a la API con un grado de paralelismo controlado, y cada tarea concurrente 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// maneja su propia lógica de descarga y guardado en la base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="authToken">El token de autenticación válido para la sesión.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="stoppingToken">El token de cancelación para detener la operación.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearNuevosTelegramasAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "--- Iniciando sondeo de Nuevos Telegramas (modo de bajo perfil) ---" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // La obtención de partidos y categorías no cambia 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  partidos  =  await  dbContext . AmbitosGeograficos . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  30  & &  a . DistritoId  ! =  null  & &  a . SeccionId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  categorias  =  await  dbContext . CategoriasElectorales . AsNoTracking ( ) . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! partidos . Any ( )  | |  ! categorias . Any ( ) )  return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  partido  in  partidos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categorias ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  listaTelegramasApi  =  await  _apiService . GetTelegramasTotalizadosAsync ( authToken ,  partido . DistritoId ! ,  partido . SeccionId ! ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( listaTelegramasApi  is  {  Count :  >  0  } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // Creamos el DbContext para la operación de guardado 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            using  var  innerScope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  innerDbContext  =  innerScope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  idsYaEnDb  =  await  innerDbContext . Telegramas 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . Where ( t  = >  listaTelegramasApi . Contains ( t . Id ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                . Select ( t  = >  t . Id ) . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  nuevosTelegramasIds  =  listaTelegramasApi . Except ( idsYaEnDb ) . ToList ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( nuevosTelegramasIds . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              _logger . LogInformation ( "Se encontraron {count} telegramas nuevos en '{partido}' para '{cat}'. Descargando..." ,  nuevosTelegramasIds . Count ,  partido . Nombre ,  categoria . Nombre ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              var  originalTimeout  =  innerDbContext . Database . GetCommandTimeout ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              try 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                innerDbContext . Database . SetCommandTimeout ( 180 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogDebug ( "Timeout de BD aumentado a 180s para descarga de telegramas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                int  contadorLote  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                const  int  tamanoLote  =  100 ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                foreach  ( var  mesaId  in  nuevosTelegramasIds ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  if  ( stoppingToken . IsCancellationRequested )  return ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-25 10:25:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  var  telegramaFile  =  await  _apiService . GetTelegramaFileAsync ( authToken ,  mesaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  if  ( telegramaFile  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-25 10:25:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    var  ambitoMesa  =  await  innerDbContext . AmbitosGeograficos . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        . FirstOrDefaultAsync ( a  = >  a . MesaId  = =  mesaId ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  ( ambitoMesa  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-25 10:25:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                      var  nuevoTelegrama  =  new  Telegrama 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:46:44 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        EleccionId  =  EleccionId , 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        Id  =  telegramaFile . NombreArchivo , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        AmbitoGeograficoId  =  ambitoMesa . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ContenidoBase64  =  telegramaFile . Imagen , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        FechaEscaneo  =  DateTime . Parse ( telegramaFile . FechaEscaneo ) . ToUniversalTime ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        FechaTotalizacion  =  DateTime . Parse ( telegramaFile . FechaTotalizacion ) . ToUniversalTime ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      await  innerDbContext . Telegramas . AddAsync ( nuevoTelegrama ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      contadorLote + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      _logger . LogWarning ( "No se encontró un ámbito geográfico para la mesa con MesaId {MesaId}. El telegrama no será guardado." ,  mesaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-25 10:25:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  await  Task . Delay ( 250 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  if  ( contadorLote  > =  tamanoLote ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    await  innerDbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _logger . LogInformation ( "Guardado un lote de {count} telegramas." ,  contadorLote ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    contadorLote  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-25 10:25:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-07 23:04:36 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( contadorLote  >  0 ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-07 23:04:36 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  await  innerDbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  _logger . LogInformation ( "Guardado el último lote de {count} telegramas." ,  contadorLote ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-07 23:04:36 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              finally 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-07 23:04:36 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                innerDbContext . Database . SetCommandTimeout ( originalTimeout ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogDebug ( "Timeout de BD restaurado a su valor original ({timeout}s)." ,  originalTimeout ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:19:16 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            }  // Fin del if (nuevosTelegramasIds.Any()) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Movemos el delay aquí para que solo se ejecute si hubo telegramas en la respuesta de la API 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  Task . Delay ( 100 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          }  // Fin del if (listaTelegramasApi is not null) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Telegramas completado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de telegramas cancelado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Telegramas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}