using Elecciones.Core.DTOs.ApiResponses;
using Elecciones.Database;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Elecciones.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
public class CatalogosController : ControllerBase
{
    private readonly EleccionesDbContext _dbContext;

    public CatalogosController(EleccionesDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet("municipios")]
    public async Task<IActionResult> GetMunicipios([FromQuery] int? categoriaId)
    {
        var municipiosQuery = _dbContext.AmbitosGeograficos
            .AsNoTracking()
            .Where(a => a.NivelId == 30);

        // --- LÓGICA UNIFICADA ---

        // Si hay una categoría, primero filtramos los municipios que son relevantes.
        if (categoriaId.HasValue)
        {
            var municipiosActivosIds = await _dbContext.ResultadosVotos
                .AsNoTracking()
                .Where(rv => rv.CategoriaId == categoriaId && rv.AmbitoGeografico.NivelId == 30)
                .Select(rv => rv.AmbitoGeografico.SeccionId)
                .Distinct()
                .ToListAsync();

            if (!municipiosActivosIds.Any()) return Ok(new List<object>());

            municipiosQuery = municipiosQuery.Where(m => m.SeccionId != null && municipiosActivosIds.Contains(m.SeccionId));
        }

        // Devolvemos siempre la misma estructura: { Id, Nombre }
        // donde 'Id' es el SeccionId, que es el que se usa en las URLs de resultados.
        var municipios = await municipiosQuery
            .OrderBy(a => a.Nombre)
            .Select(a => new { Id = a.SeccionId, a.Nombre })
            .ToListAsync();

        return Ok(municipios);
    }

    [HttpGet("agrupaciones")]
    public async Task<IActionResult> GetAgrupaciones()
    {
        var agrupaciones = await _dbContext.AgrupacionesPoliticas
            .AsNoTracking()
            .Select(a => new { a.Id, a.Nombre })
            .ToListAsync();
        return Ok(agrupaciones);
    }

    [HttpGet("secciones-electorales")]
    public async Task<IActionResult> GetSeccionesElectorales([FromQuery] int? categoriaId)
    {
        var seccionesQuery = _dbContext.AmbitosGeograficos
            .AsNoTracking()
            .Where(a => a.NivelId == 20); // Nivel 20 = Sección Electoral

        if (categoriaId == null)
        {
            var todasLasSecciones = await seccionesQuery
                .OrderBy(a => a.Nombre)
                .Select(a => new { Id = a.SeccionProvincialId, a.Nombre })
                .ToListAsync();
            return Ok(todasLasSecciones);
        }

        // --- LÓGICA DE FILTRADO CORREGIDA Y MÁS ROBUSTA ---
        // Usamos los ResultadosVotos como fuente, ya que es más probable que existan
        // que las proyecciones de bancas en todo momento.
        // Buscamos los municipios que tienen votos para esta categoría.
        var municipiosConVotos = await _dbContext.ResultadosVotos
            .AsNoTracking()
            .Where(rv => rv.CategoriaId == categoriaId)
            .Select(rv => rv.AmbitoGeografico.SeccionProvincialId) // De aquí sacamos la sección electoral
            .Distinct()
            .ToListAsync();

        if (!municipiosConVotos.Any())
        {
            // Si no hay ningún voto en absoluto, devolvemos vacío (esto es correcto).
            return Ok(new List<object>());
        }

        var seccionesFiltradas = await seccionesQuery
            .Where(s => s.SeccionProvincialId != null && municipiosConVotos.Contains(s.SeccionProvincialId))
            .OrderBy(a => a.Nombre)
            .Select(a => new { Id = a.SeccionProvincialId, a.Nombre })
            .ToListAsync();

        return Ok(seccionesFiltradas);
    }

    // Nivel 20: Sección Electoral
    [HttpGet("secciones")]
    public async Task<IActionResult> GetSecciones()
    {
        var secciones = await _dbContext.AmbitosGeograficos.AsNoTracking()
            .Where(a => a.NivelId == 20 && !string.IsNullOrEmpty(a.SeccionProvincialId))
            .Select(a => new { Id = a.SeccionProvincialId, a.Nombre })
            .Distinct().OrderBy(s => s.Nombre).ToListAsync();
        return Ok(secciones);
    }

    // Nivel 30: Municipio (llamado "Sección" por la API)
    [HttpGet("municipios/{seccionProvincialId}")]
    public async Task<IActionResult> GetMunicipiosPorSeccion(string seccionProvincialId)
    {
        var municipios = await _dbContext.AmbitosGeograficos.AsNoTracking()
            .Where(a => a.NivelId == 30 && a.SeccionProvincialId == seccionProvincialId && !string.IsNullOrEmpty(a.SeccionId))
            .Select(a => new { Id = a.SeccionId, a.Nombre }) // El ID del Municipio es SeccionId
            .Distinct().OrderBy(m => m.Nombre).ToListAsync();
        return Ok(municipios);
    }

    // Nivel 50: Circuito (llamado "Municipio" por la API)
    [HttpGet("circuitos/{municipioId}")]
    public async Task<IActionResult> GetCircuitosPorMunicipio(string municipioId)
    {
        var circuitos = await _dbContext.AmbitosGeograficos.AsNoTracking()
            // Un Circuito (Nivel 50) pertenece a un Municipio (Nivel 30) a través del campo 'SeccionId'
            .Where(a => a.NivelId == 50 && a.SeccionId == municipioId && !string.IsNullOrEmpty(a.CircuitoId))
            .Select(a => new { Id = a.CircuitoId, a.Nombre })
            .Distinct().OrderBy(c => c.Nombre).ToListAsync();
        return Ok(circuitos);
    }

    // Nivel 60: Establecimiento (llamado "Colegio" por la API)
    [HttpGet("establecimientos/{circuitoId}")]
    public async Task<IActionResult> GetEstablecimientosPorCircuito(string circuitoId)
    {
        var establecimientos = await _dbContext.AmbitosGeograficos.AsNoTracking()
            .Where(a => a.NivelId == 60 && a.CircuitoId == circuitoId && !string.IsNullOrEmpty(a.EstablecimientoId))
            .Select(a => new { Id = a.EstablecimientoId, a.Nombre })
            .Distinct().OrderBy(e => e.Nombre).ToListAsync();
        return Ok(establecimientos);
    }

    // Nivel 70: Mesa
    [HttpGet("mesas/{establecimientoId}")]
    public async Task<IActionResult> GetMesasPorEstablecimiento(string establecimientoId)
    {
        var mesas = await _dbContext.AmbitosGeograficos.AsNoTracking()
            .Where(a => a.NivelId == 70 && a.EstablecimientoId == establecimientoId && !string.IsNullOrEmpty(a.MesaId))
            .Select(a => new { Id = a.MesaId, a.Nombre })
            .Distinct().OrderBy(m => m.Nombre).ToListAsync();
        return Ok(mesas);
    }

    /// <summary>
    /// Obtiene todos los establecimientos de un municipio, sin necesidad de especificar un circuito.
    /// </summary>
    [HttpGet("establecimientos-por-municipio/{municipioId}")]
    public async Task<IActionResult> GetEstablecimientosPorMunicipio(string municipioId)
    {
        // Buscamos todos los ámbitos de Nivel 60 (Establecimiento) que pertenezcan
        // al Municipio (Nivel 30) a través del campo 'SeccionId'.
        var establecimientos = await _dbContext.AmbitosGeograficos.AsNoTracking()
            .Where(a => a.NivelId == 60 && a.SeccionId == municipioId && !string.IsNullOrEmpty(a.EstablecimientoId))
            .Select(a => new { Id = a.EstablecimientoId, a.Nombre })
            .Distinct()
            .OrderBy(e => e.Nombre)
            .ToListAsync();

        return Ok(establecimientos);
    }

    /// <summary>
    /// Obtiene la lista de municipios (partidos) para un distrito (provincia) específico.
    /// </summary>
    [HttpGet("municipios-por-distrito/{distritoId}")]
    public async Task<IActionResult> GetMunicipiosPorDistrito(string distritoId)
    {
        var municipios = await _dbContext.AmbitosGeograficos
            .AsNoTracking()
            .Where(a => a.NivelId == 30 && a.DistritoId == distritoId) // Nivel 30 = Municipio
            .OrderBy(a => a.Nombre)
            .Select(a => new { Id = a.Id.ToString(), a.Nombre }) // Devolvemos el ID de la BD como string
            .ToListAsync();

        return Ok(municipios);
    }
}