// ui/visor/ventana_visor.rs — GR Visor de Pautaje
//
// Muestra en tiempo real todo lo pautado para el día en curso:
//   • Tabla superior: Eventos, Comerciales y Eventos en Espera
//     agrupados por corte (hora:minuto), coloreados por tipo
//   • Tabla inferior: Parrilla musical de la hora actual y la siguiente
//
// Se actualiza automáticamente cada 60 segundos.

use gtk4 as gtk;
use gtk::prelude::*;
use gtk::{
    Application, ApplicationWindow, Box as GtkBox, Button, Label,
    Orientation, Paned, ScrolledWindow,
    TreeView, TreeViewColumn, CellRendererText, ListStore,
};
use glib;
use chrono::{Local, Datelike, Timelike};

use crate::i18n::tr;
use crate::models::{EntradaPautaje, TipoPautaje};
use crate::storage;
use crate::storage_parrilla;
use crate::ui::comun;
use crate::skin;

const ICONO_VISOR: &[u8] = include_bytes!("../../../assets/visor48x48.png");

// ─── Paleta de colores suaves con buen contraste ─────────────────────────
// Fondos claros/medios con texto oscuro garantizan legibilidad

// Pautaje — cabeceras de tipo (fondo más saturado, texto oscuro)
const COLOR_CAB_EVENTOS:      &str = "#b2dfdb"; // teal claro
const COLOR_CAB_COMERCIALES:  &str = "#c8e6c9"; // verde claro
const COLOR_CAB_ESPERA:       &str = "#e1bee7"; // lavanda claro

// Pautaje — ítems individuales (fondo más suave)
const COLOR_ITEM_EVENTOS:     &str = "#e0f2f1"; // teal muy claro
const COLOR_ITEM_COMERCIALES: &str = "#f1f8e9"; // verde muy claro
const COLOR_ITEM_ESPERA:      &str = "#f3e5f5"; // lavanda muy claro

// Texto oscuro para fondos claros
const FG_EVENTOS:             &str = "#004d40"; // teal oscuro
const FG_COMERCIALES:         &str = "#1b5e20"; // verde oscuro
const FG_ESPERA:              &str = "#4a148c"; // púrpura oscuro
const FG_CAB:                 &str = "#212121"; // negro suave para cabeceras

// Parrilla — fondo azul medio con texto blanco
const COLOR_PARRILLA_HORA:    &str = "#1565c0"; // azul medio
const FG_PARRILLA_HORA:       &str = "#ffffff";
const COLOR_PARRILLA_ITEM:    &str = "#e3f2fd"; // azul muy claro
const FG_PARRILLA_ITEM:       &str = "#0d47a1"; // azul oscuro legible
const COLOR_PARRILLA_HORA_MK: &str = "#fff9c4"; // amarillo claro para ⏰ Hora
const FG_PARRILLA_HORA_MK:    &str = "#e65100"; // naranja oscuro

// ─── Ventana principal ─────────────────────────────────────────────────────

pub fn construir_ventana_visor(app: &Application) {
    let ventana = ApplicationWindow::builder()
        .application(app)
        .title(tr("visor.win_title"))
        .default_width(580)
        .default_height(700)
        .build();

    // CSS
    let css = gtk::CssProvider::new();
    css.load_from_data(concat!(
        "label.visor-titulo { font-weight:bold; font-size:11pt;",
        "  padding:6px 12px; background:#1565c0; color:white;",
        "  border-radius:4px; }",
        "label.visor-sub { font-size:9pt; color:#546e7a; padding:2px 8px; }",
        "button.btn-actualizar { padding:4px 12px; }",
    ));
    gtk::style_context_add_provider_for_display(
        &gtk4::prelude::WidgetExt::display(&ventana),
        &css,
        gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
    );
    skin::aplicar_css_extra(&gtk4::prelude::WidgetExt::display(&ventana));

    let vbox = GtkBox::new(Orientation::Vertical, 0);

    // ── Encabezado ────────────────────────────────────────────────────────
    let hbox_enc = GtkBox::new(Orientation::Horizontal, 8);
    hbox_enc.set_margin_start(8);
    hbox_enc.set_margin_end(8);
    hbox_enc.set_margin_top(4);
    hbox_enc.set_margin_bottom(4);

    let lbl_titulo = Label::new(Some(tr("visor.header")));
    lbl_titulo.add_css_class("visor-titulo");
    lbl_titulo.set_hexpand(true);
    lbl_titulo.set_halign(gtk::Align::Center);

    let btn_actualizar = Button::with_label(tr("visor.btn_refresh"));
    btn_actualizar.add_css_class("btn-actualizar");

    hbox_enc.append(&lbl_titulo);
    hbox_enc.append(&btn_actualizar);
    vbox.append(&hbox_enc);

    // ── Paned: tabla pautaje (arriba) | parrilla (abajo) ─────────────────
    let paned = Paned::new(Orientation::Vertical);
    paned.set_vexpand(true);
    paned.set_position(500);

    // ── Panel superior: tabla de pautaje del día ──────────────────────────
    let (store_pautaje, tree_pautaje) = construir_tabla_pautaje();
    let lbl_pautaje = Label::new(Some(tr("visor.pautaje_dia")));
    lbl_pautaje.add_css_class("visor-sub");
    lbl_pautaje.set_halign(gtk::Align::Start);
    lbl_pautaje.set_margin_start(8);

    let vbox_top = GtkBox::new(Orientation::Vertical, 0);
    vbox_top.append(&lbl_pautaje);
    let scroll_top = ScrolledWindow::new();
    scroll_top.set_vexpand(true);
    scroll_top.set_child(Some(&tree_pautaje));
    vbox_top.append(&scroll_top);
    paned.set_start_child(Some(&vbox_top));

    // ── Panel inferior: parrilla hora actual y siguiente ──────────────────
    let (store_parrilla, tree_parrilla) = construir_tabla_parrilla();
    let lbl_parrilla_titulo = Label::new(None);
    lbl_parrilla_titulo.add_css_class("visor-sub");
    lbl_parrilla_titulo.set_halign(gtk::Align::Start);
    lbl_parrilla_titulo.set_margin_start(8);
    lbl_parrilla_titulo.set_margin_top(4);

    let vbox_bot = GtkBox::new(Orientation::Vertical, 0);
    vbox_bot.append(&lbl_parrilla_titulo);
    let scroll_bot = ScrolledWindow::new();
    scroll_bot.set_vexpand(true);
    scroll_bot.set_child(Some(&tree_parrilla));
    vbox_bot.append(&scroll_bot);
    paned.set_end_child(Some(&vbox_bot));

    vbox.append(&paned);
    ventana.set_child(Some(&vbox));

    // ── Carga inicial ─────────────────────────────────────────────────────
    let sp = store_pautaje.clone();
    let spar = store_parrilla.clone();
    let lbl_par = lbl_parrilla_titulo.clone();
    cargar_todo(&sp, &spar, &lbl_par);

    // ── Botón actualizar ──────────────────────────────────────────────────
    {
        let sp2 = store_pautaje.clone();
        let spar2 = store_parrilla.clone();
        let lbl2 = lbl_parrilla_titulo.clone();
        btn_actualizar.connect_clicked(move |_| {
            cargar_todo(&sp2, &spar2, &lbl2);
        });
    }

    // ── Auto-actualización cada 60 segundos ───────────────────────────────
    {
        let sp3 = store_pautaje.clone();
        let spar3 = store_parrilla.clone();
        let lbl3 = lbl_parrilla_titulo.clone();
        glib::timeout_add_seconds_local(60, move || {
            cargar_todo(&sp3, &spar3, &lbl3);
            glib::ControlFlow::Continue
        });
    }

    comun::aplicar_icono_ventana(&ventana, &skin::icono("visor48x48.png", ICONO_VISOR));
    comun::aplicar_tamanio_ventana(&ventana, 600, 680);
    ventana.present();
}

// ─── Estructura de las tablas ──────────────────────────────────────────────

/// Tabla de pautaje: 5 columnas + color de fondo/frente
/// cols: 0=Comercial/Evento  1=Tiempo  2=Días  3=Inicio  4=Fin
///       5=bg_color(str)  6=fg_color(str)  7=weight(i32)
fn construir_tabla_pautaje() -> (ListStore, TreeView) {
    let store = ListStore::new(&[
        glib::Type::STRING, // 0 Comercial/Evento
        glib::Type::STRING, // 1 Tiempo
        glib::Type::STRING, // 2 Días
        glib::Type::STRING, // 3 Inicio
        glib::Type::STRING, // 4 Fin
        glib::Type::STRING, // 5 bg color
        glib::Type::STRING, // 6 fg color
        glib::Type::I32,    // 7 peso (bold=700, normal=400)
    ]);

    let tree = TreeView::with_model(&store);
    tree.set_headers_visible(true);
    tree.set_grid_lines(gtk::TreeViewGridLines::Horizontal);

    let cols = [
        (tr("visor.col_nombre"), 0, 200),
        (tr("visor.col_tiempo"), 1,  60),
        (tr("visor.col_dias"),   2,  70),
        (tr("visor.col_inicio"), 3,  80),
        (tr("visor.col_fin"),    4,  80),
    ];
    for (titulo, idx, ancho) in cols {
        let renderer = CellRendererText::new();
        let col = TreeViewColumn::new();
        col.set_title(titulo);
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text",            idx);
        col.add_attribute(&renderer, "background",      5);
        col.add_attribute(&renderer, "foreground",      6);
        col.add_attribute(&renderer, "weight",          7);
        col.set_resizable(true);
        col.set_min_width(ancho);
        tree.append_column(&col);
    }
    (store, tree)
}

/// Tabla de parrilla: 1 columna + color
/// cols: 0=ruta/item  1=bg  2=fg  3=weight
fn construir_tabla_parrilla() -> (ListStore, TreeView) {
    let store = ListStore::new(&[
        glib::Type::STRING, // 0 ítem
        glib::Type::STRING, // 1 bg color
        glib::Type::STRING, // 2 fg color
        glib::Type::I32,    // 3 weight
    ]);

    let tree = TreeView::with_model(&store);
    tree.set_headers_visible(false);

    let renderer = CellRendererText::new();
    let col = TreeViewColumn::new();
    col.pack_start(&renderer, true);
    col.add_attribute(&renderer, "text",       0);
    col.add_attribute(&renderer, "background", 1);
    col.add_attribute(&renderer, "foreground", 2);
    col.add_attribute(&renderer, "weight",     3);
    tree.append_column(&col);

    (store, tree)
}

// ─── Carga de datos ────────────────────────────────────────────────────────

fn cargar_todo(
    store_pautaje: &ListStore,
    store_parrilla: &ListStore,
    lbl_parrilla: &Label,
) {
    let ahora = Local::now();
    let hoy = ahora.date_naive();
    let hora_actual = ahora.hour() as u8;
    let dia_semana = hoy.weekday().number_from_monday() as u8; // 1=Lun..7=Dom

    cargar_pautaje(store_pautaje, hoy, dia_semana);
    cargar_parrilla(store_parrilla, lbl_parrilla, dia_semana, hora_actual);
}

// ─── Pautaje del día ───────────────────────────────────────────────────────

fn cargar_pautaje(store: &ListStore, hoy: chrono::NaiveDate, dia_semana: u8) {
    store.clear();

    let dia_char = char::from_digit(dia_semana as u32, 10).unwrap_or('1');

    // Recorrer todas las horas y minutos
    for hora in 0u8..24 {
        for minuto in (0u8..60).step_by(5) {
            let mut filas_corte: Vec<FilaVisor> = Vec::new();

            // Los tres tipos en orden: Eventos, Comerciales, Eventos en Espera
            for (tipo, color_cab, fg_cab, color_item, fg_item) in &[
                (TipoPautaje::Eventos,        COLOR_CAB_EVENTOS,     FG_EVENTOS,     COLOR_ITEM_EVENTOS,     FG_EVENTOS),
                (TipoPautaje::Comerciales,    COLOR_CAB_COMERCIALES, FG_COMERCIALES, COLOR_ITEM_COMERCIALES, FG_COMERCIALES),
                (TipoPautaje::EventosEnEspera,COLOR_CAB_ESPERA,      FG_ESPERA,      COLOR_ITEM_ESPERA,      FG_ESPERA),
            ] {
                let entradas = storage::leer_entradas(tipo, hora, minuto);
                // Filtrar por día activo y vigente
                let entradas: Vec<_> = entradas.iter()
                    .filter(|e| {
                        e.dias.contains(dia_char)
                            && e.inicio <= hoy
                            && e.fin >= hoy
                    })
                    .collect();

                if entradas.is_empty() { continue; }

                // Fila cabecera del tipo
                filas_corte.push(FilaVisor {
                    nombre: format!("=={}", tipo.label().to_uppercase()),
                    tiempo: format!("{}:{:02}", hora, minuto),
                    dias: "=======".to_string(),
                    inicio: "========".to_string(),
                    fin: "========".to_string(),
                    bg: color_cab.to_string(),
                    fg: fg_cab.to_string(),
                    bold: true,
                });

                for entrada in entradas {
                    // Si la ruta termina en /* es una carpeta aleatoria
                    let (nombre, tiempo) = if entrada.ruta.ends_with("/*") {
                        // Quitar el /* final y tomar el nombre de la carpeta
                        let carpeta = entrada.ruta.trim_end_matches("/*");
                        let nombre_carpeta = std::path::Path::new(carpeta)
                            .file_name()
                            .and_then(|n| n.to_str())
                            .unwrap_or(carpeta);
                        let nombre = format!("{}-{}", nombre_carpeta, tr("visor.aleatorio"));

                        // Duración: leer el primer audio de la carpeta
                        let duracion = primer_audio_carpeta(carpeta);
                        let tiempo = crate::duracion_audio::formato_duracion(duracion);
                        (nombre, tiempo)
                    } else {
                        // Archivo individual, URL o lista .gradio
                        let dur = if entrada.ruta.ends_with(".gradio") {
                            tr("visor.lista").to_string()
                        } else {
                            entrada.duracion_fmt()
                        };
                        (entrada.nombre_display(), dur)
                    };

                    filas_corte.push(FilaVisor {
                        nombre,
                        tiempo,
                        dias: entrada.dias.clone(),
                        inicio: entrada.inicio.format("%Y%m%d").to_string(),
                        fin: entrada.fin.format("%Y%m%d").to_string(),
                        bg: color_item.to_string(),
                        fg: fg_item.to_string(),
                        bold: false,
                    });
                }
            }

            // Solo agregar filas si hay algo en este corte
            for fila in filas_corte {
                store.insert_with_values(None, &[
                    (0, &fila.nombre),
                    (1, &fila.tiempo),
                    (2, &fila.dias),
                    (3, &fila.inicio),
                    (4, &fila.fin),
                    (5, &fila.bg),
                    (6, &fila.fg),
                    (7, &(if fila.bold { 700i32 } else { 400i32 })),
                ]);
            }
        }
    }
}

// ─── Parrilla musical ──────────────────────────────────────────────────────

fn cargar_parrilla(
    store: &ListStore,
    lbl: &Label,
    dia_semana: u8,
    hora_actual: u8,
) {
    store.clear();

    let hora_siguiente = (hora_actual + 1) % 24;
    lbl.set_text(
        &tr("visor.parrilla_header")
            .replace("{h}",  &format!("{:02}", hora_actual))
            .replace("{hs}", &format!("{:02}", hora_siguiente))
    );

    // Hora actual
    agregar_bloque_parrilla(store, dia_semana, hora_actual, tr("visor.hora_actual"));
    // Hora siguiente
    agregar_bloque_parrilla(store, dia_semana, hora_siguiente, tr("visor.hora_siguiente"));
}

fn agregar_bloque_parrilla(
    store: &ListStore,
    dia_semana: u8,
    hora: u8,
    etiqueta: &str,
) {
    let siguiente = hora + 1; // 23-24.mus
    let archivo = format!("{}-{}.mus", hora, siguiente);

    // Fila cabecera
    store.insert_with_values(None, &[
        (0, &format!("══ {} {:02}:00 ══ ({})", etiqueta, hora, archivo)),
        (1, &COLOR_PARRILLA_HORA.to_string()),
        (2, &FG_PARRILLA_HORA.to_string()),
        (3, &700i32),
    ]);

    let items = storage_parrilla::leer_items(dia_semana, hora);

    if items.is_empty() {
        store.insert_with_values(None, &[
            (0, &format!("  {}", tr("visor.sin_programacion"))),
            (1, &"#f5f5f5".to_string()),
            (2, &"#9e9e9e".to_string()),
            (3, &400i32),
        ]);
    } else {
        for item in &items {
            let (texto, bg, fg) = if item == "Hora" {
                (
                    format!("  ⏰  Hora"),
                    COLOR_PARRILLA_HORA_MK.to_string(),
                    FG_PARRILLA_HORA_MK.to_string(),
                )
            } else {
                // Mostrar la ruta completa (incluye ruta/* para carpetas)
                (
                    format!("  {}", item),
                    COLOR_PARRILLA_ITEM.to_string(),
                    FG_PARRILLA_ITEM.to_string(),
                )
            };
            store.insert_with_values(None, &[
                (0, &texto),
                (1, &bg),
                (2, &fg),
                (3, &400i32),
            ]);
        }
    }

    // Separador visual
    store.insert_with_values(None, &[
        (0, &""),
        (1, &"#e0e0e0".to_string()),
        (2, &"#e0e0e0".to_string()),
        (3, &400i32),
    ]);
}

// ─── Estructura auxiliar ───────────────────────────────────────────────────

struct FilaVisor {
    nombre: String,
    tiempo: String,
    dias: String,
    inicio: String,
    fin: String,
    bg: String,
    fg: String,
    bold: bool,
}

// ─── Helpers ───────────────────────────────────────────────────────────────

/// Lee la duración del primer archivo de audio encontrado en una carpeta.
/// Retorna 0 si la carpeta no existe o no tiene audios.
/// Solo un archivo — rápido para el visor.
fn primer_audio_carpeta(carpeta: &str) -> u64 {
    const EXTS: &[&str] = &["mp3", "wav", "ogg", "flac", "aac", "m4a"];
    let dir = match std::fs::read_dir(carpeta) {
        Ok(d) => d,
        Err(_) => return 0,
    };
    let mut archivos: Vec<std::path::PathBuf> = dir
        .filter_map(|e| e.ok())
        .map(|e| e.path())
        .filter(|p| {
            p.is_file() && p.extension()
                .and_then(|x| x.to_str())
                .map(|x| EXTS.contains(&x.to_lowercase().as_str()))
                .unwrap_or(false)
        })
        .collect();
    archivos.sort(); // tomar el primero en orden alfabético
    archivos.first()
        .map(|p| crate::duracion_audio::leer_duracion(&p.to_string_lossy()))
        .unwrap_or(0)
}
