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);

        // Si NO se proporciona una categoriaId, devolvemos todos (para Concejales).
        if (categoriaId == null)
        {
            var todosLosMunicipios = await municipiosQuery
                .OrderBy(a => a.Nombre)
                .Select(a => new { a.SeccionId, a.Nombre }) // Usamos SeccionId como el ID electoral
                .ToListAsync();
            return Ok(todosLosMunicipios);
        }

        // --- LÓGICA DE FILTRADO PARA DIPUTADOS Y SENADORES ---
        // 1. Encontrar las Secciones Electorales que SÍ tienen resultados para la categoría.
        var seccionesActivasIds = await _dbContext.ProyeccionesBancas
            .AsNoTracking()
            .Where(p => p.CategoriaId == categoriaId)
            .Select(p => p.AmbitoGeografico.SeccionProvincialId)
            .Distinct()
            .ToListAsync();

        // 2. Filtramos la lista de municipios.
        var municipiosFiltrados = await municipiosQuery
            .Where(m => seccionesActivasIds.Contains(m.SeccionProvincialId))
            .OrderBy(a => a.Nombre)
            .Select(a => new { a.SeccionId, a.Nombre })
            .ToListAsync();

        return Ok(municipiosFiltrados);
    }

    [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

        // Si NO se proporciona una categoriaId, devolvemos todas las secciones.
        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 ---
        // 1. Encontrar las Secciones Provinciales que SÍ tienen resultados para la categoría solicitada.
        //    Usamos ProyeccionesBancas como fuente de verdad, ya que es el dato más relevante.
        var seccionesActivasIds = await _dbContext.ProyeccionesBancas
            .AsNoTracking()
            .Where(p => p.CategoriaId == categoriaId)
            .Select(p => p.AmbitoGeografico.SeccionProvincialId)
            .Distinct()
            .ToListAsync();

        // 2. Filtramos la lista de secciones.
        var seccionesFiltradas = await seccionesQuery
            .Where(s => seccionesActivasIds.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);
    }
}