// ui/panel_arbol.rs — Panel izquierdo: árbol de carpetas + lista de archivos
//
// Árbol con carga lazy (bajo demanda) para evitar congelamiento.
// Cada directorio muestra un hijo "cargando..." que se reemplaza al expandir.

use gtk4 as gtk;
use gtk::prelude::*;
use gtk::{
    Box as GtkBox, Label, ListStore, Orientation, Paned, ScrolledWindow,
    TreeStore, TreeView, TreeViewColumn, CellRendererText, TreeIter,
};
use glib;
use std::cell::RefCell;
use std::rc::Rc;
use std::path::{Path, PathBuf};

use crate::i18n::tr;
use crate::models::{EntradaPautaje, Estado};
use crate::storage;
use crate::ui::comun::recargar_store;

// Valor centinela para nodos no expandidos aún
const DUMMY: &str = "⟳";

pub fn construir_panel_arbol(
    estado: Rc<RefCell<Estado>>,
    store_pautaje: ListStore,
    _lbl_acumulado: Label,
    _lbl_corte: Label,
) -> GtkBox {
    let vbox = GtkBox::new(Orientation::Vertical, 0);
    vbox.set_width_request(380);

    // TreeStore: nombre_visible | ruta | es_archivo
    let tree_store = TreeStore::new(&[
        glib::Type::STRING,
        glib::Type::STRING,
        glib::Type::BOOL,
    ]);

    poblar_raiz(&tree_store);

    let tree_view = TreeView::with_model(&tree_store);
    tree_view.set_headers_visible(false);
    tree_view.set_enable_tree_lines(true);
    {
        let r = CellRendererText::new();
        let c = TreeViewColumn::new();
        c.pack_start(&r, true);
        c.add_attribute(&r, "text", 0);
        tree_view.append_column(&c);
    }

    // Carga lazy: al expandir un nodo, poblar sus hijos reales
    {
        let ts = tree_store.clone();
        tree_view.connect_row_expanded(move |_tv, iter, _path| {
            expandir_nodo(&ts, iter);
        });
    }

    // ListStore de archivos: nombre | ruta
    let store_archivos = ListStore::new(&[glib::Type::STRING, glib::Type::STRING]);

    let list_view = TreeView::with_model(&store_archivos);
    list_view.set_headers_visible(true);
    {
        let r = CellRendererText::new();
        let c = TreeViewColumn::new();
        c.set_title(tr("parr.col_nombre"));
        c.pack_start(&r, true);
        c.add_attribute(&r, "text", 0);
        list_view.append_column(&c);
    }

    // Seleccionar carpeta → poblar archivos
    {
        let sa = store_archivos.clone();
        tree_view.selection().connect_changed(move |sel| {
            if let Some((model, iter)) = sel.selected() {
                let es_archivo: bool = model.get::<bool>(&iter, 2);
                if !es_archivo {
                    let ruta: String = model.get::<String>(&iter, 1);
                    poblar_archivos(&sa, &ruta);
                }
            }
        });
    }

    // Doble clic en archivo → agregar al pautaje
    {
        let ec = estado.clone();
        let sp = store_pautaje.clone();
        let sa = store_archivos.clone();
        list_view.connect_row_activated(move |_v, path, _col| {
            if let Some(iter) = sa.iter(path) {
                let ruta: String = sa.get::<String>(&iter, 1);
                agregar_al_pautaje(&ec, &sp, &ruta);
            }
        });
    }

    let scroll_arbol = ScrolledWindow::new();
    scroll_arbol.set_vexpand(true);
    scroll_arbol.set_min_content_height(300);
    scroll_arbol.set_child(Some(&tree_view));

    let scroll_archivos = ScrolledWindow::new();
    scroll_archivos.set_vexpand(true);
    scroll_archivos.set_min_content_height(150);
    scroll_archivos.set_child(Some(&list_view));

    let paned = Paned::new(Orientation::Vertical);
    paned.set_position(300);
    paned.set_start_child(Some(&scroll_arbol));
    paned.set_end_child(Some(&scroll_archivos));

    vbox.append(&paned);
    vbox
}

// ─── Poblar raíz ───────────────────────────────────────────────────────────

fn poblar_raiz(store: &TreeStore) {
    store.clear();
    let home = dirs::home_dir()
        .unwrap_or_else(|| std::path::PathBuf::from("/root"))
        .to_string_lossy()
        .into_owned();

    // Nodo Inicio ($HOME) — expandir primer nivel
    let iter_home = store.insert_with_values(None, None, &[
        (0, &format!("🏠 {}", tr("tree.home"))),
        (1, &home),
        (2, &false),
    ]);
    agregar_hijos_lazy(store, &iter_home, &PathBuf::from(&home));

    // Nodo Sistema (/) — solo mostrar, carga lazy al expandir
    let iter_sys = store.insert_with_values(None, None, &[
        (0, &format!("💾 {} (/)", tr("tree.system"))),
        (1, &"/".to_string()),
        (2, &false),
    ]);
    // Añadir dummy para que muestre la flecha de expansión
    store.insert_with_values(Some(&iter_sys), None, &[
        (0, &DUMMY.to_string()),
        (1, &"".to_string()),
        (2, &false),
    ]);
}

// ─── Carga lazy al expandir ────────────────────────────────────────────────

fn expandir_nodo(store: &TreeStore, iter: &TreeIter) {
    // Comprobar si el único hijo es el dummy
    let n_hijos = store.iter_n_children(Some(iter));
    if n_hijos != 1 { return; }

    let hijo = match store.iter_children(Some(iter)) {
        Some(h) => h,
        None => return,
    };
    let nombre: String = store.get::<String>(&hijo, 0);
    if nombre != DUMMY { return; }

    // Es dummy: reemplazar con hijos reales
    let ruta: String = store.get::<String>(iter, 1);
    store.remove(&hijo);
    agregar_hijos_lazy(store, iter, &PathBuf::from(&ruta));
}

fn agregar_hijos_lazy(store: &TreeStore, padre: &TreeIter, dir: &Path) {
    let subdirs = match std::fs::read_dir(dir) {
        Ok(d) => d,
        Err(_) => return,
    };
    let mut dirs: Vec<PathBuf> = subdirs
        .filter_map(|e| e.ok())
        .map(|e| e.path())
        .filter(|p| p.is_dir() && !p.file_name()
            .and_then(|n| n.to_str())
            .map(|n| n.starts_with('.'))
            .unwrap_or(true))
        .collect();
    dirs.sort();

    for subdir in dirs {
        let nombre = subdir.file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("?")
            .to_string();
        let iter = store.insert_with_values(Some(padre), None, &[
            (0, &format!("📁 {}", nombre)),
            (1, &subdir.to_string_lossy().to_string()),
            (2, &false),
        ]);
        // Añadir dummy si tiene subdirectorios
        if tiene_subdirs(&subdir) {
            store.insert_with_values(Some(&iter), None, &[
                (0, &DUMMY.to_string()),
                (1, &"".to_string()),
                (2, &false),
            ]);
        }
    }
}

fn tiene_subdirs(dir: &Path) -> bool {
    std::fs::read_dir(dir)
        .map(|mut d| d.any(|e| e.map(|e| e.path().is_dir()).unwrap_or(false)))
        .unwrap_or(false)
}

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

fn poblar_archivos(store: &ListStore, ruta: &str) {
    store.clear();
    // Primera fila: pautar toda la carpeta aleatoriamente
    store.insert_with_values(None, &[
        (0, &format!("📁  {}", tr("arbol.pautar_carpeta"))),
        (1, &format!("{}/*", ruta)),
    ]);
    const EXTS: &[&str] = &["mp3", "wav", "ogg", "flac", "aac", "m4a", "gradio"];
    if let Ok(entradas) = std::fs::read_dir(ruta) {
        let mut archivos: Vec<PathBuf> = entradas
            .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();
        for archivo in archivos {
            let nombre = archivo.file_name()
                .and_then(|n| n.to_str()).unwrap_or("?").to_string();
            store.insert_with_values(None, &[
                (0, &nombre),
                (1, &archivo.to_string_lossy().to_string()),
            ]);
        }
    }
}

fn agregar_al_pautaje(
    estado: &Rc<RefCell<Estado>>,
    store_pautaje: &ListStore,
    ruta: &str,
) {
    let e = estado.borrow();
    let entrada = EntradaPautaje {
        ruta: ruta.to_string(),
        dias: e.dias.clone(),
        inicio: e.fecha_inicio,
        fin: e.fecha_fin,
    };
    storage::agregar_entrada(&e.tipo, e.hora, e.minuto, entrada);
    recargar_store(store_pautaje, &e.tipo, e.hora, e.minuto);
}
