// storage.rs — Lectura y escritura de archivos .com
//
// Estructura en disco:
//   $HOME/.gradio/data/comerciales/{hora}/{minuto}.com
//   $HOME/.gradio/data/eventos/{hora}/{minuto}.com
//   $HOME/.gradio/data/eventos-espera/{hora}/{minuto}.com
//
// Donde hora ∈ [0,23] y minuto ∈ {0,5,10,…,55}

use std::fs;
use std::path::{Path, PathBuf};
use chrono::NaiveDate;

use crate::models::{EntradaPautaje, TipoPautaje};

// ─── Rutas ─────────────────────────────────────────────────────────────────

pub fn directorio_base() -> PathBuf {
    dirs::home_dir()
        .unwrap_or_else(std::env::temp_dir)
        .join(".gradio").join("data")
}

pub fn ruta_archivo(tipo: &TipoPautaje, hora: u8, minuto: u8) -> PathBuf {
    directorio_base()
        .join(tipo.carpeta())
        .join(hora.to_string())
        .join(format!("{}.com", minuto))
}

/// Crea todos los directorios necesarios (se llama una vez al arranque)
pub fn crear_directorios() {
    let base = directorio_base();
    for tipo in &[
        TipoPautaje::Comerciales,
        TipoPautaje::Eventos,
        TipoPautaje::EventosEnEspera,
    ] {
        for hora in 0u8..24 {
            let _ = fs::create_dir_all(base.join(tipo.carpeta()).join(hora.to_string()));
        }
    }
}

// ─── Lectura ───────────────────────────────────────────────────────────────

pub fn leer_entradas(tipo: &TipoPautaje, hora: u8, minuto: u8) -> Vec<EntradaPautaje> {
    leer_desde(&ruta_archivo(tipo, hora, minuto))
}

fn leer_desde(ruta: &Path) -> Vec<EntradaPautaje> {
    match fs::read_to_string(ruta) {
        Ok(contenido) => contenido
            .lines()
            .filter(|l| !l.trim().is_empty())
            .filter_map(EntradaPautaje::parsear)
            .collect(),
        Err(_) => Vec::new(),
    }
}

// ─── Escritura ─────────────────────────────────────────────────────────────

pub fn escribir_entradas(tipo: &TipoPautaje, hora: u8, minuto: u8, entradas: &[EntradaPautaje]) {
    let ruta = ruta_archivo(tipo, hora, minuto);
    if let Some(padre) = ruta.parent() {
        let _ = fs::create_dir_all(padre);
    }
    let contenido: String = entradas.iter().map(|e| e.serializar()).collect();
    let _ = fs::write(&ruta, contenido);
}

// ─── Operaciones de alto nivel ─────────────────────────────────────────────

/// Agrega una entrada al corte (sin duplicar por contenido idéntico)
pub fn agregar_entrada(tipo: &TipoPautaje, hora: u8, minuto: u8, entrada: EntradaPautaje) {
    let mut entradas = leer_entradas(tipo, hora, minuto);
    if !entradas.iter().any(|e| e.serializar() == entrada.serializar()) {
        entradas.push(entrada);
        escribir_entradas(tipo, hora, minuto, &entradas);
    }
}

/// Agrega una entrada siempre, sin verificar duplicados (usado para "Hora")
pub fn agregar_entrada_siempre(tipo: &TipoPautaje, hora: u8, minuto: u8, entrada: EntradaPautaje) {
    let mut entradas = leer_entradas(tipo, hora, minuto);
    entradas.push(entrada);
    escribir_entradas(tipo, hora, minuto, &entradas);
}

/// Mueve una entrada hacia arriba (subir=true) o hacia abajo (subir=false)
pub fn mover_entrada(tipo: &TipoPautaje, hora: u8, minuto: u8, indice: usize, subir: bool) {
    let mut entradas = leer_entradas(tipo, hora, minuto);
    if subir && indice > 0 {
        entradas.swap(indice, indice - 1);
    } else if !subir && indice + 1 < entradas.len() {
        entradas.swap(indice, indice + 1);
    } else {
        return; // sin cambios
    }
    escribir_entradas(tipo, hora, minuto, &entradas);
}

/// Elimina la entrada en el índice dado
pub fn eliminar_entrada(tipo: &TipoPautaje, hora: u8, minuto: u8, indice: usize) {
    let mut entradas = leer_entradas(tipo, hora, minuto);
    if indice < entradas.len() {
        entradas.remove(indice);
        escribir_entradas(tipo, hora, minuto, &entradas);
    }
}

/// Elimina de todos los archivos .com las entradas cuya fecha de fin < hoy.
/// Retorna el número total de entradas eliminadas.
pub fn limpiar_caducados(hoy: NaiveDate) -> usize {
    let base = directorio_base();
    let mut total = 0usize;

    for tipo in &[
        TipoPautaje::Comerciales,
        TipoPautaje::Eventos,
        TipoPautaje::EventosEnEspera,
    ] {
        for hora in 0u8..24 {
            for minuto in (0u8..60).step_by(5) {
                let ruta = base
                    .join(tipo.carpeta())
                    .join(hora.to_string())
                    .join(format!("{}.com", minuto));
                if !ruta.exists() { continue; }

                let antes = leer_desde(&ruta);
                let n_antes = antes.len();
                let despues: Vec<_> = antes.into_iter().filter(|e| e.fin >= hoy).collect();
                let n_despues = despues.len();

                if n_antes != n_despues {
                    total += n_antes - n_despues;
                    let contenido: String = despues.iter().map(|e| e.serializar()).collect();
                    let _ = fs::write(&ruta, contenido);
                }
            }
        }
    }
    total
}
