// ui/parrilla/ventana_parrilla.rs — Parrilla Musical Específica de G-Radio

use gtk4 as gtk;
use gtk::prelude::*;
use gtk::{
    Application, ApplicationWindow, Box as GtkBox, Button, Entry, Frame, Image,
    FileChooserAction, FileChooserDialog, Label, ListStore, Orientation,
    Paned, ScrolledWindow, Separator,
    TreeStore, TreeView, TreeViewColumn, CellRendererText, TreeIter,
    SelectionMode, DragSource, DropTarget,
};
use gtk::gdk;
use gtk::gio;
use gdk4::FileList;
use glib;
use std::cell::RefCell;
use std::rc::Rc;
use std::path::PathBuf;

use crate::i18n::tr;
use crate::storage_parrilla;
use crate::ui::comun;
use crate::skin;

const ICONO_PARRILLA: &[u8] = include_bytes!("../../../assets/parrilla48x48.png");
const ICON_TRASH:     &[u8] = include_bytes!("../../../assets/trash.png");
const ICON_UP:        &[u8] = include_bytes!("../../../assets/up.png");
const ICON_DOWN:      &[u8] = include_bytes!("../../../assets/down.png");

fn icon_btn(data: &[u8], tooltip: &str) -> Button {
    let btn = Button::new();
    btn.set_tooltip_text(Some(tooltip));
    let loader = gdk4::gdk_pixbuf::PixbufLoader::new();
    loader.write(data).unwrap_or(());
    loader.close().unwrap_or(());
    if let Some(pixbuf) = loader.pixbuf() {
        if let Some(scaled) = pixbuf.scale_simple(
            22, 22, gdk4::gdk_pixbuf::InterpType::Bilinear,
        ) {
            let texture = gdk4::Texture::for_pixbuf(&scaled);
            let image = Image::from_paintable(Some(&texture));
            btn.set_child(Some(&image));
        }
    }
    btn
}

// ─── Estado ────────────────────────────────────────────────────────────────

#[derive(Debug)]
struct EstadoParrilla {
    dia: u8,
    hora: u8,
}

impl Default for EstadoParrilla {
    fn default() -> Self { EstadoParrilla { dia: 1, hora: 0 } }
}

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

pub fn construir_ventana_parrilla(app: &Application) {
    storage_parrilla::crear_directorios();

    let estado = Rc::new(RefCell::new(EstadoParrilla::default()));

    let ventana = ApplicationWindow::builder()
        .application(app)
        .title(tr("parr.win_title"))
        .default_width(1010)
        .default_height(700)
        .build();

    // CSS registrado usando el display de la ventana — garantizado válido
    let css = gtk::CssProvider::new();
    css.load_from_data(concat!(
        // Seleccionados — rojo
        "button.hora-sel {",
        "  background: #b71c1c; color: white;",
        "  padding: 4px 2px; min-height: 24px;",
        "}",
        "button.hora-sel:hover { background: #c62828; }",
        "button.dia-sel {",
        "  background: #b71c1c; color: white;",
        "  padding: 6px 4px; min-height: 28px;",
        "}",
        "button.dia-sel:hover { background: #c62828; }",
        // Botón Grabar
        "button.grabar-btn {",
        "  background: #b71c1c; color: white; font-weight: bold;",
        "  padding: 6px 4px; min-height: 28px;",
        "}",
        "button.grabar-btn:hover { background: #c62828; }",
        // Arrastrando
        "button.arrastrando { opacity: 0.4; }",
        // Etiquetas
        "label.titulo { font-weight: bold; font-size: 11pt; }",
        "label.subtitulo { font-size: 8pt; color: #aaaaaa; }",
    ));
    // Usar el display de la ventana, no el default global
    gtk::style_context_add_provider_for_display(
        &gtk4::prelude::WidgetExt::display(&ventana),
        &css,
        gtk::STYLE_PROVIDER_PRIORITY_USER,
    );
    skin::aplicar_css_extra(&gtk4::prelude::WidgetExt::display(&ventana));

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

    // ── Encabezado ───────────────────────────────────────────────────────────
    let hbox_titulo = GtkBox::new(Orientation::Horizontal, 6);
    hbox_titulo.set_margin_start(8);
    hbox_titulo.set_margin_end(8);
    hbox_titulo.set_margin_top(6);

    let lbl_titulo = Label::new(Some(tr("parr.titulo")));
    lbl_titulo.add_css_class("titulo");
    lbl_titulo.set_halign(gtk::Align::Start);
    hbox_titulo.append(&lbl_titulo);

    let spacer_titulo = GtkBox::new(Orientation::Horizontal, 0);
    spacer_titulo.set_hexpand(true);
    hbox_titulo.append(&spacer_titulo);

    let lbl_pis = Label::new(Some(tr("parr.pisadores_hora")));
    hbox_titulo.append(&lbl_pis);

    let entry_pis = Entry::new();
    entry_pis.set_width_chars(30);
    entry_pis.set_placeholder_text(Some(tr("parr.pisadores_ph")));
    entry_pis.set_hexpand(false);
    hbox_titulo.append(&entry_pis);

    let btn_pis_browse = Button::with_label("📂");
    btn_pis_browse.set_tooltip_text(Some(tr("parr.pis_browse_tip")));
    hbox_titulo.append(&btn_pis_browse);

    // Conectar botón de exploración de carpeta de pisadores
    {
        let entry_ref = entry_pis.clone();
        let win_ref   = ventana.clone();
        btn_pis_browse.connect_clicked(move |_| {
            let fc = FileChooserDialog::new(
                Some(tr("parr.pis_browse_tip")),
                Some(&win_ref),
                FileChooserAction::SelectFolder,
                &[(tr("btn.cancel"),    gtk::ResponseType::Cancel),
                  (tr("btn.select"),    gtk::ResponseType::Accept)],
            );
            fc.set_modal(true);
            if !entry_ref.text().is_empty() {
                let _ = fc.set_current_folder(
                    Some(&gio::File::for_path(entry_ref.text().as_str()))
                );
            }
            let entry_c = entry_ref.clone();
            fc.connect_response(move |fc, resp| {
                if resp == gtk::ResponseType::Accept {
                    if let Some(file) = fc.file() {
                        if let Some(path) = file.path() {
                            entry_c.set_text(&path.to_string_lossy());
                        }
                    }
                }
                fc.close();
            });
            fc.present();
        });
    }

    vbox_raiz.append(&hbox_titulo);

    let lbl_sub = Label::new(Some(tr("parr.fuentes_audio")));
    lbl_sub.add_css_class("subtitulo");
    lbl_sub.set_halign(gtk::Align::Start);
    lbl_sub.set_margin_start(8);
    vbox_raiz.append(&lbl_sub);
    vbox_raiz.append(&Separator::new(Orientation::Horizontal));

    // ListStore: columna 0 = texto del ítem
    let store_items = ListStore::new(&[glib::Type::STRING]);

    let tree_items = Rc::new({
        let t = TreeView::with_model(&store_items);
        t.set_headers_visible(false);
        t.selection().set_mode(SelectionMode::Single);
        let renderer = CellRendererText::new();
        let col = TreeViewColumn::new();
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", 0);
        t.append_column(&col);
        t
    });

    // ── Layout: izquierda | (centro + derecha) ────────────────────────────
    let paned_main = Paned::new(Orientation::Horizontal);
    paned_main.set_vexpand(true);
    paned_main.set_position(390);

    let panel_izq = construir_panel_izquierdo(
        store_items.clone(),
        tree_items.clone(),
    );
    paned_main.set_start_child(Some(&panel_izq));

    let hbox_der = GtkBox::new(Orientation::Horizontal, 0);
    hbox_der.set_hexpand(true);
    hbox_der.set_vexpand(true);

    let panel_centro = construir_panel_centro(
        store_items.clone(),
        tree_items.clone(),
    );
    panel_centro.set_hexpand(true);
    hbox_der.append(&panel_centro);
    hbox_der.append(&Separator::new(Orientation::Vertical));

    let panel_der = construir_panel_derecho(
        estado.clone(),
        store_items.clone(),
        entry_pis.clone(),
    );
    hbox_der.append(&panel_der);

    paned_main.set_end_child(Some(&hbox_der));
    vbox_raiz.append(&paned_main);

    ventana.set_child(Some(&vbox_raiz));
    comun::aplicar_icono_ventana(&ventana, &skin::icono("parrilla48x48.png", ICONO_PARRILLA));
    comun::aplicar_tamanio_ventana(&ventana, 1100, 700);
    ventana.present();
}

// ─── Panel izquierdo ──────────────────────────────────────────────────────

fn construir_panel_izquierdo(
    store_items: ListStore,
    tree_items: Rc<TreeView>,
) -> GtkBox {
    let vbox = GtkBox::new(Orientation::Vertical, 0);
    vbox.set_width_request(390);

    let tree_store = TreeStore::new(&[
        glib::Type::STRING,
        glib::Type::STRING,
        glib::Type::BOOL,
    ]);
    poblar_arbol(&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
    {
        let ts = tree_store.clone();
        tree_view.connect_row_expanded(move |_tv, iter, _path| {
            expandir_nodo_par(&ts, iter);
        });
    }

    let store_arch = ListStore::new(&[glib::Type::STRING, glib::Type::STRING]);

    let list_arch = TreeView::with_model(&store_arch);
    list_arch.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_arch.append_column(&c);
    }

    {
        let sa = store_arch.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);
                }
            }
        });
    }

    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        let sa = store_arch.clone();
        list_arch.connect_row_activated(move |_v, path, _col| {
            if let Some(iter) = sa.iter(path) {
                let ruta: String = sa.get::<String>(&iter, 1);
                agregar_item_ui(&si, &ti, ruta);
            }
        });
    }

    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        tree_view.connect_row_activated(move |view, path, _col| {
            if let Some((model, iter)) = view.model().and_then(|m| m.iter(path).map(|i| (m, i))) {
                let es_archivo: bool = model.get::<bool>(&iter, 2);
                if !es_archivo {
                    let ruta: String = model.get::<String>(&iter, 1);
                    agregar_item_ui(&si, &ti, format!("{}/*", ruta));
                }
            }
        });
    }

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

    let scroll_arch = ScrolledWindow::new();
    scroll_arch.set_vexpand(true);
    scroll_arch.set_min_content_height(130);
    scroll_arch.set_child(Some(&list_arch));

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

    vbox.append(&paned);
    vbox
}

// ─── Panel central ────────────────────────────────────────────────────────

fn construir_panel_centro(
    store_items: ListStore,
    tree_items: Rc<TreeView>,
) -> GtkBox {
    let vbox = GtkBox::new(Orientation::Vertical, 0);
    vbox.set_hexpand(true);

    let hbox_btns = GtkBox::new(Orientation::Horizontal, 4);
    hbox_btns.set_margin_start(4);
    hbox_btns.set_margin_end(4);
    hbox_btns.set_margin_top(4);
    hbox_btns.set_margin_bottom(4);

    let btn_hora = Button::with_label("⏰");
    btn_hora.set_tooltip_text(Some(tr("parr.btn_marca_hora")));
    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        btn_hora.connect_clicked(move |_| {
            agregar_item_ui(&si, &ti, "Hora".to_string());
        });
    }
    hbox_btns.append(&btn_hora);

    let btn_subir = icon_btn(&skin::icono("up.png", ICON_UP), tr("parr.subir_item"));
    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        btn_subir.connect_clicked(move |_| {
            if let Some(idx) = seleccion_indice(&ti) {
                mover_en_store(&si, idx, true);
                seleccionar_fila_items(&ti, idx.saturating_sub(1));
            }
        });
    }
    hbox_btns.append(&btn_subir);

    let btn_bajar = icon_btn(&skin::icono("down.png", ICON_DOWN), tr("parr.bajar_item"));
    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        btn_bajar.connect_clicked(move |_| {
            if let Some(idx) = seleccion_indice(&ti) {
                let n = store_items_count(&si);
                mover_en_store(&si, idx, false);
                seleccionar_fila_items(&ti, (idx + 1).min(n.saturating_sub(1)));
            }
        });
    }
    hbox_btns.append(&btn_bajar);

    let btn_del = icon_btn(&skin::icono("trash.png", ICON_TRASH), tr("parr.eliminar_item"));
    {
        let si = store_items.clone();
        let ti = tree_items.clone();
        btn_del.connect_clicked(move |_| {
            if let Some(idx) = seleccion_indice(&ti) {
                eliminar_en_store(&si, idx);
            }
        });
    }
    hbox_btns.append(&btn_del);

    hbox_btns.append(&Separator::new(Orientation::Vertical));
    let lbl = Label::new(Some(tr("parr.parrilla_musical")));
    lbl.set_hexpand(true);
    lbl.set_halign(gtk::Align::End);
    hbox_btns.append(&lbl);

    vbox.append(&hbox_btns);
    vbox.append(&Separator::new(Orientation::Horizontal));

    // ── DropTarget para archivos externos desde Nemo (igual que botonera) ──
    {
        let si = store_items.clone();
        let ti = tree_items.clone();

        let drop_target = DropTarget::new(gtk::gio::File::static_type(), gdk::DragAction::COPY);

        drop_target.connect_drop(move |_, value, _, _| {
            if let Ok(file) = value.get::<gtk::gio::File>() {
                if let Some(path) = file.path() {
                    // Si es carpeta, agregar con /* (aleatorio)
                    if path.is_dir() {
                        let ruta = format!("{}/*", path.to_string_lossy());
                        agregar_item_ui(&si, &ti, ruta);
                        return true;
                    }
                    // Si es archivo de audio, agregar directamente
                    let ext = path.extension()
                        .and_then(|e| e.to_str())
                        .unwrap_or("")
                        .to_lowercase();
                    if matches!(ext.as_str(), "mp3"|"wav"|"ogg"|"flac"|"aac"|"m4a") {
                        agregar_item_ui(&si, &ti, path.to_string_lossy().to_string());
                        return true;
                    }
                }
            }
            false
        });

        tree_items.add_controller(drop_target);
    }

    let scroll = ScrolledWindow::new();
    scroll.set_hexpand(true);
    scroll.set_vexpand(true);
    scroll.set_child(Some(tree_items.as_ref()));
    vbox.append(&scroll);

    vbox
}

// ─── Panel derecho ────────────────────────────────────────────────────────
//
// Drag & Drop — formato de datos transferidos: texto simple
//   "H:nn"   → arrastrando hora nn  (ej: "H:05")
//   "D:n"    → arrastrando día n    (ej: "D:3" = Miércoles)

fn construir_panel_derecho(
    estado: Rc<RefCell<EstadoParrilla>>,
    store_items: ListStore,
    entry_pis: Entry,
) -> GtkBox {
    let vbox = GtkBox::new(Orientation::Vertical, 6);
    vbox.set_width_request(220);
    vbox.set_margin_start(4);
    vbox.set_margin_end(4);
    vbox.set_margin_top(4);
    vbox.set_margin_bottom(4);

    // Tipo de dato para drag & drop: String con formato "H:nn" o "D:n"

    // ── Leer / Grabar — acceso rápido sobre "Horas" ───────────────────────
    let hbox_acc = GtkBox::new(Orientation::Horizontal, 4);

    let btn_leer = Button::with_label(tr("parr.btn_leer"));
    btn_leer.set_hexpand(true);
    btn_leer.set_tooltip_text(Some(tr("parr.btn_leer_tip")));
    {
        let ec = estado.clone();
        let si = store_items.clone();
        let ep = entry_pis.clone();
        btn_leer.connect_clicked(move |_| {
            let e = ec.borrow();
            recargar_items(&si, e.dia, e.hora);
            ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
        });
    }
    hbox_acc.append(&btn_leer);

    let btn_grabar = Button::with_label(tr("parr.btn_grabar"));
    btn_grabar.set_hexpand(true);
    btn_grabar.add_css_class("grabar-btn");
    btn_grabar.set_tooltip_text(Some(tr("parr.btn_grabar_tip")));
    {
        let ec = estado.clone();
        let si = store_items.clone();
        let ep = entry_pis.clone();
        btn_grabar.connect_clicked(move |_| {
            let e = ec.borrow();
            let items = store_a_vec(&si);
            storage_parrilla::escribir_items(e.dia, e.hora, &items);
            storage_parrilla::escribir_pisador_dir(e.dia, e.hora, &ep.text());
        });
    }
    hbox_acc.append(&btn_grabar);
    vbox.append(&hbox_acc);

    // ── Frame de horas ────────────────────────────────────────────────────
    let frame_horas = Frame::new(Some(tr("parr.frame_horas")));
    let grid_horas = gtk::Grid::new();
    grid_horas.set_column_spacing(2);
    grid_horas.set_row_spacing(2);
    grid_horas.set_column_homogeneous(true);
    grid_horas.set_margin_top(4);
    grid_horas.set_margin_bottom(4);
    grid_horas.set_margin_start(4);
    grid_horas.set_margin_end(4);

    let btns_hora: Vec<Button> = (0u8..24).map(|h| {
        let b = Button::with_label(&format!("{:02}", h));
        b.set_hexpand(true);
        b
    }).collect();

    btns_hora[0].add_css_class("hora-sel");

    for (i, btn) in btns_hora.iter().enumerate() {
        let col = (i / 8) as i32;
        let row = (i % 8) as i32;
        grid_horas.attach(btn, col, row, 1, 1);

        let h = i as u8;

        // ── Clic → seleccionar hora ──
        {
            let ec = estado.clone();
            let si = store_items.clone();
            let ep = entry_pis.clone();
            let btns_c = btns_hora.clone();
            btn.connect_clicked(move |b| {
                for bh in &btns_c { bh.remove_css_class("hora-sel"); }
                b.add_css_class("hora-sel");
                ec.borrow_mut().hora = h;
                let e = ec.borrow();
                recargar_items(&si, e.dia, e.hora);
                ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
            });
        }

        // ── DragSource en el Label interno del botón (no en el botón) ──
        // Así el DragSource no compite con el GestureClick del Button
        let drag_src = DragSource::new();
        drag_src.set_actions(gdk::DragAction::COPY);
        {
            let payload = format!("H:{}", h);
            drag_src.connect_prepare(move |_, _, _| {
                Some(gdk::ContentProvider::for_value(&payload.to_value()))
            });
            let btn_c2 = btn.clone();
            drag_src.connect_drag_begin(move |_, _| {
                btn_c2.add_css_class("arrastrando");
            });
            let btn_c3 = btn.clone();
            drag_src.connect_drag_end(move |_, _, _| {
                btn_c3.remove_css_class("arrastrando");
            });
        }
        // Adjuntar DragSource al Label interno del botón, no al botón
        if let Some(lbl) = btn.child() {
            lbl.add_controller(drag_src);
        } else {
            btn.add_controller(drag_src);
        }
        btn.set_tooltip_text(Some(
            &tr("parr.tip_hora").replace("{h}", &format!("{:02}", h))
        ));

        // ── DropTarget en el botón ──
        let drop_tgt = DropTarget::new(glib::Type::STRING, gdk::DragAction::COPY);
        {
            let ec = estado.clone();
            let si = store_items.clone();
            let ep = entry_pis.clone();
            let btns_c = btns_hora.clone();
            let h_dest = h;
            drop_tgt.connect_drop(move |_, value, _, _| {
                let payload = value.get::<String>().unwrap_or_default();
                let dia_actual = ec.borrow().dia;
                if let Some(rest) = payload.strip_prefix("H:") {
                    // Hora → hora: copiar en el mismo día (incluye pisador_dir)
                    if let Ok(h_orig) = rest.parse::<u8>() {
                        storage_parrilla::copiar_hora(dia_actual, h_orig, dia_actual, h_dest);
                        for bh in &btns_c { bh.remove_css_class("hora-sel"); }
                        btns_c[h_dest as usize].add_css_class("hora-sel");
                        ec.borrow_mut().hora = h_dest;
                        recargar_items(&si, dia_actual, h_dest);
                        ep.set_text(&storage_parrilla::leer_pisador_dir(dia_actual, h_dest));
                    }
                } else if let Some(rest) = payload.strip_prefix("D:") {
                    // Día → hora: copiar esa hora del día origen al día actual
                    if let Ok(d_orig) = rest.parse::<u8>() {
                        storage_parrilla::copiar_hora(d_orig, h_dest, dia_actual, h_dest);
                        let e = ec.borrow();
                        if e.hora == h_dest {
                            recargar_items(&si, e.dia, e.hora);
                            ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
                        }
                    }
                }
                true
            });
        }
        btn.add_controller(drop_tgt);
    }
    frame_horas.set_child(Some(&grid_horas));
    vbox.append(&frame_horas);

    // ── Frame de días ─────────────────────────────────────────────────────
    let frame_dias = Frame::new(Some(tr("parr.frame_dia")));
    let vbox_dias = GtkBox::new(Orientation::Vertical, 2);
    vbox_dias.set_margin_top(4);
    vbox_dias.set_margin_bottom(4);
    vbox_dias.set_margin_start(4);
    vbox_dias.set_margin_end(4);

    let nombres_dias = [
        tr("dia.lunes"),
        tr("dia.martes"),
        tr("dia.miercoles"),
        tr("dia.jueves"),
        tr("dia.viernes"),
        tr("dia.sabado"),
        tr("dia.domingo"),
    ];

    let btns_dia: Vec<Button> = nombres_dias.iter().map(|n| {
        let b = Button::with_label(n);
        b.set_hexpand(true);
        b
    }).collect();

    btns_dia[0].add_css_class("dia-sel");

    for (i, btn) in btns_dia.iter().enumerate() {
        let d = (i + 1) as u8;

        // ── Clic → seleccionar día ──
        {
            let ec = estado.clone();
            let si = store_items.clone();
            let ep = entry_pis.clone();
            let btns_c = btns_dia.clone();
            btn.connect_clicked(move |b| {
                for bd in &btns_c { bd.remove_css_class("dia-sel"); }
                b.add_css_class("dia-sel");
                ec.borrow_mut().dia = d;
                let e = ec.borrow();
                recargar_items(&si, e.dia, e.hora);
                ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
            });
        }

        // ── DragSource en el Label interno ──
        let drag_src = DragSource::new();
        drag_src.set_actions(gdk::DragAction::COPY);
        {
            let payload = format!("D:{}", d);
            drag_src.connect_prepare(move |_, _, _| {
                Some(gdk::ContentProvider::for_value(&payload.to_value()))
            });
            let btn_c = btn.clone();
            drag_src.connect_drag_begin(move |_, _| {
                btn_c.add_css_class("arrastrando");
            });
            let btn_c2 = btn.clone();
            drag_src.connect_drag_end(move |_, _, _| {
                btn_c2.remove_css_class("arrastrando");
            });
        }
        if let Some(lbl) = btn.child() {
            lbl.add_controller(drag_src);
        } else {
            btn.add_controller(drag_src);
        }
        btn.set_tooltip_text(Some(
            &tr("parr.tip_dia").replace("{d}", nombres_dias[i])
        ));

        // ── DropTarget en el botón ──
        let drop_tgt = DropTarget::new(glib::Type::STRING, gdk::DragAction::COPY);
        {
            let ec = estado.clone();
            let si = store_items.clone();
            let ep = entry_pis.clone();
            let btns_c_dia = btns_dia.clone();
            let d_dest = d;
            drop_tgt.connect_drop(move |_, value, _, _| {
                let payload = value.get::<String>().unwrap_or_default();
                if let Some(rest) = payload.strip_prefix("H:") {
                    if let Ok(h_orig) = rest.parse::<u8>() {
                        let dia_actual = ec.borrow().dia;
                        storage_parrilla::copiar_hora(dia_actual, h_orig, d_dest, h_orig);
                        for bd in &btns_c_dia { bd.remove_css_class("dia-sel"); }
                        btns_c_dia[(d_dest - 1) as usize].add_css_class("dia-sel");
                        ec.borrow_mut().dia = d_dest;
                        let e = ec.borrow();
                        recargar_items(&si, e.dia, e.hora);
                        ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
                    }
                } else if let Some(rest) = payload.strip_prefix("D:") {
                    if let Ok(d_orig) = rest.parse::<u8>() {
                        if d_orig != d_dest {
                            storage_parrilla::copiar_dia(d_orig, d_dest);
                            for bd in &btns_c_dia { bd.remove_css_class("dia-sel"); }
                            btns_c_dia[(d_dest - 1) as usize].add_css_class("dia-sel");
                            ec.borrow_mut().dia = d_dest;
                            let e = ec.borrow();
                            recargar_items(&si, e.dia, e.hora);
                            ep.set_text(&storage_parrilla::leer_pisador_dir(e.dia, e.hora));
                        }
                    }
                }
                true
            });
        }
        btn.add_controller(drop_tgt);
        vbox_dias.append(btn);
    }
    frame_dias.set_child(Some(&vbox_dias));
    vbox.append(&frame_dias);

    vbox
}

// ─── Helpers de árbol/archivos ─────────────────────────────────────────────

const DUMMY_PARRILLA: &str = "⟳";

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

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

    // Sistema: lazy
    let iter_sys = store.insert_with_values(None, None, &[
        (0, &format!("💾 {} (/)", tr("tree.system"))),
        (1, &"/".to_string()),
        (2, &false),
    ]);
    store.insert_with_values(Some(&iter_sys), None, &[
        (0, &DUMMY_PARRILLA.to_string()),
        (1, &"".to_string()),
        (2, &false),
    ]);
}

fn agregar_hijos_lazy_par(store: &TreeStore, padre: &TreeIter, dir: &std::path::Path) {
    let subdirs_iter = match std::fs::read_dir(dir) { Ok(d) => d, Err(_) => return };
    let mut dirs: Vec<PathBuf> = subdirs_iter
        .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),
        ]);
        // Dummy si tiene subdirectorios
        if std::fs::read_dir(&subdir)
            .map(|mut d| d.any(|e| e.map(|e| e.path().is_dir()).unwrap_or(false)))
            .unwrap_or(false)
        {
            store.insert_with_values(Some(&iter), None, &[
                (0, &DUMMY_PARRILLA.to_string()),
                (1, &"".to_string()),
                (2, &false),
            ]);
        }
    }
}

fn expandir_nodo_par(store: &TreeStore, iter: &TreeIter) {
    if store.iter_n_children(Some(iter)) != 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_PARRILLA { return; }
    let ruta: String = store.get::<String>(iter, 1);
    store.remove(&hijo);
    agregar_hijos_lazy_par(store, iter, &PathBuf::from(&ruta));
}



fn poblar_archivos(store: &ListStore, ruta: &str) {
    store.clear();
    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 a in archivos {
            let nombre = a.file_name().and_then(|n| n.to_str()).unwrap_or("?").to_string();
            store.insert_with_values(None, &[
                (0, &nombre),
                (1, &a.to_string_lossy().to_string()),
            ]);
        }
    }
}

// ─── Helpers de lista central ──────────────────────────────────────────────

fn agregar_item_ui(store: &ListStore, tree: &Rc<TreeView>, item: String) {
    store.insert_with_values(None, &[(0, &item)]);
    let n = store_items_count(store);
    if n > 0 { seleccionar_fila_items(tree, n - 1); }
}

fn recargar_items(store: &ListStore, dia: u8, hora: u8) {
    store.clear();
    for item in storage_parrilla::leer_items(dia, hora) {
        store.insert_with_values(None, &[(0, &item)]);
    }
}

fn store_a_vec(store: &ListStore) -> Vec<String> {
    let mut v = Vec::new();
    if let Some(iter) = store.iter_first() {
        loop {
            v.push(store.get::<String>(&iter, 0));
            if !store.iter_next(&iter) { break; }
        }
    }
    v
}

fn store_items_count(store: &ListStore) -> usize {
    store.iter_n_children(None) as usize
}

fn seleccion_indice(tree: &TreeView) -> Option<usize> {
    let (paths, _) = tree.selection().selected_rows();
    paths.first().and_then(|p| p.indices().first().map(|i| *i as usize))
}

fn seleccionar_fila_items(tree: &TreeView, idx: usize) {
    if let Some(path) = gtk::TreePath::from_string(&idx.to_string()) {
        tree.selection().select_path(&path);
        tree.scroll_to_cell(Some(&path), None::<&TreeViewColumn>, false, 0.0, 0.0);
    }
}

fn mover_en_store(store: &ListStore, idx: usize, subir: bool) {
    let mut items = store_a_vec(store);
    if subir && idx > 0 { items.swap(idx, idx - 1); }
    else if !subir && idx + 1 < items.len() { items.swap(idx, idx + 1); }
    else { return; }
    store.clear();
    for item in &items { store.insert_with_values(None, &[(0, item)]); }
}

fn eliminar_en_store(store: &ListStore, idx: usize) {
    if let Some(path) = gtk::TreePath::from_string(&idx.to_string()) {
        if let Some(iter) = store.iter(&path) { store.remove(&iter); }
    }
}
