use adw::prelude::*;
use gtk::glib;
use std::cell::Cell;
use std::rc::Rc;

use crate::app::AppState;

pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage {
    let cfg = state.job_config.borrow();

    // === OUTER LAYOUT ===
    let outer = gtk::Box::builder()
        .orientation(gtk::Orientation::Vertical)
        .spacing(0)
        .vexpand(true)
        .build();

    // --- Enable toggle (full width) ---
    let enable_group = adw::PreferencesGroup::builder()
        .margin_start(12)
        .margin_end(12)
        .margin_top(12)
        .build();
    let enable_row = adw::SwitchRow::builder()
        .title("Enable Watermark")
        .subtitle("Add text or image watermark to processed images")
        .active(cfg.watermark_enabled)
        .tooltip_text("Toggle watermark on or off")
        .build();
    enable_group.add(&enable_row);
    outer.append(&enable_group);

    // === LEFT SIDE: Preview ===

    let preview_picture = gtk::Picture::builder()
        .content_fit(gtk::ContentFit::Contain)
        .hexpand(true)
        .vexpand(true)
        .build();
    preview_picture.set_can_target(true);
    preview_picture.set_focusable(true);
    preview_picture.update_property(&[
        gtk::accessible::Property::Label("Watermark preview - press Space to cycle images"),
    ]);

    let info_label = gtk::Label::builder()
        .label("No images loaded")
        .css_classes(["dim-label", "caption"])
        .halign(gtk::Align::Center)
        .margin_top(4)
        .margin_bottom(4)
        .build();

    let preview_frame = gtk::Frame::builder()
        .hexpand(true)
        .vexpand(true)
        .build();
    preview_frame.set_child(Some(&preview_picture));

    let preview_box = gtk::Box::builder()
        .orientation(gtk::Orientation::Vertical)
        .spacing(4)
        .hexpand(true)
        .vexpand(true)
        .build();
    preview_box.append(&preview_frame);
    preview_box.append(&info_label);

    // === RIGHT SIDE: Controls (scrollable) ===

    let controls = gtk::Box::builder()
        .orientation(gtk::Orientation::Vertical)
        .spacing(12)
        .margin_start(12)
        .build();

    // --- Watermark type ---
    let type_group = adw::PreferencesGroup::builder()
        .title("Watermark Type")
        .build();

    let type_row = adw::ComboRow::builder()
        .title("Type")
        .subtitle("Choose text or image watermark")
        .use_subtitle(true)
        .tooltip_text("Choose between text or image/logo overlay")
        .build();
    type_row.set_model(Some(&gtk::StringList::new(&["Text Watermark", "Image Watermark"])));
    type_row.set_list_factory(Some(&super::full_text_list_factory()));
    type_row.set_selected(if cfg.watermark_use_image { 1 } else { 0 });

    type_group.add(&type_row);
    controls.append(&type_group);

    // --- Text watermark settings ---
    let text_group = adw::PreferencesGroup::builder()
        .title("Text Watermark")
        .visible(!cfg.watermark_use_image)
        .build();

    let text_row = adw::EntryRow::builder()
        .title("Watermark Text")
        .text(&cfg.watermark_text)
        .tooltip_text("The text that appears as a watermark on each image")
        .build();

    let font_row = adw::ActionRow::builder()
        .title("Font Family")
        .subtitle("Choose a typeface for the watermark text")
        .build();

    let font_dialog = gtk::FontDialog::builder()
        .title("Choose Watermark Font")
        .modal(true)
        .build();
    let font_button = gtk::FontDialogButton::builder()
        .dialog(&font_dialog)
        .valign(gtk::Align::Center)
        .build();

    if !cfg.watermark_font_family.is_empty() {
        let desc = gtk::pango::FontDescription::from_string(&cfg.watermark_font_family);
        font_button.set_font_desc(&desc);
    }
    font_button.update_property(&[
        gtk::accessible::Property::Label("Choose watermark font"),
    ]);
    font_row.add_suffix(&font_button);

    let font_size_row = adw::SpinRow::builder()
        .title("Font Size")
        .subtitle("Size in pixels")
        .adjustment(&gtk::Adjustment::new(cfg.watermark_font_size as f64, 8.0, 200.0, 1.0, 10.0, 0.0))
        .tooltip_text("Size of watermark text in pixels")
        .build();

    text_group.add(&text_row);
    text_group.add(&font_row);
    text_group.add(&font_size_row);
    controls.append(&text_group);

    // --- Image watermark settings ---
    let image_group = adw::PreferencesGroup::builder()
        .title("Image Watermark")
        .visible(cfg.watermark_use_image)
        .build();

    let image_path_row = adw::ActionRow::builder()
        .title("Logo Image")
        .subtitle(
            cfg.watermark_image_path
                .as_ref()
                .map(|p| p.display().to_string())
                .unwrap_or_else(|| "No image selected".to_string()),
        )
        .activatable(true)
        .build();
    let image_prefix_icon = gtk::Image::from_icon_name("image-x-generic-symbolic");
    image_prefix_icon.set_accessible_role(gtk::AccessibleRole::Presentation);
    image_path_row.add_prefix(&image_prefix_icon);

    let choose_image_button = gtk::Button::builder()
        .icon_name("document-open-symbolic")
        .tooltip_text("Choose logo image")
        .valign(gtk::Align::Center)
        .has_frame(false)
        .build();
    choose_image_button.update_property(&[
        gtk::accessible::Property::Label("Choose logo image"),
    ]);
    image_path_row.add_suffix(&choose_image_button);

    image_group.add(&image_path_row);
    controls.append(&image_group);

    // --- Position group with 3x3 grid ---
    let position_group = adw::PreferencesGroup::builder()
        .title("Position")
        .description("Choose where the watermark appears on the image")
        .build();

    let position_names = [
        "Top Left", "Top Center", "Top Right",
        "Middle Left", "Center", "Middle Right",
        "Bottom Left", "Bottom Center", "Bottom Right",
    ];

    let grid = gtk::Grid::builder()
        .row_spacing(4)
        .column_spacing(4)
        .halign(gtk::Align::Center)
        .margin_top(8)
        .margin_bottom(8)
        .build();

    // Frame styled to look like a miniature image
    let grid_outer = gtk::Box::builder()
        .orientation(gtk::Orientation::Vertical)
        .halign(gtk::Align::Center)
        .build();

    let grid_frame = gtk::Frame::builder()
        .halign(gtk::Align::Center)
        .build();
    grid_frame.set_child(Some(&grid));
    grid_frame.update_property(&[
        gtk::accessible::Property::Label("Watermark position grid. Select where the watermark appears on the image."),
    ]);

    // Image outline label above the grid
    let grid_title = gtk::Label::builder()
        .label("Image")
        .css_classes(["dim-label", "caption"])
        .halign(gtk::Align::Center)
        .margin_bottom(4)
        .build();

    grid_outer.append(&grid_title);
    grid_outer.append(&grid_frame);

    let mut first_button: Option<gtk::ToggleButton> = None;
    let buttons: Vec<gtk::ToggleButton> = position_names.iter().enumerate().map(|(i, name)| {
        let btn = gtk::ToggleButton::builder()
            .tooltip_text(*name)
            .width_request(48)
            .height_request(48)
            .build();

        btn.update_property(&[
            gtk::accessible::Property::Label(&format!("Watermark position: {}", name)),
        ]);

        let icon = if i == cfg.watermark_position as usize {
            "radio-checked-symbolic"
        } else {
            "radio-symbolic"
        };
        btn.set_child(Some(&gtk::Image::from_icon_name(icon)));
        btn.set_active(i == cfg.watermark_position as usize);

        if let Some(ref first) = first_button {
            btn.set_group(Some(first));
        } else {
            first_button = Some(btn.clone());
        }

        let row = i / 3;
        let col = i % 3;
        grid.attach(&btn, col as i32, row as i32, 1, 1);

        btn
    }).collect();

    position_group.add(&grid_outer);

    let position_label = gtk::Label::builder()
        .label(position_names.get(cfg.watermark_position as usize).copied().unwrap_or("Center"))
        .css_classes(["dim-label"])
        .halign(gtk::Align::Center)
        .margin_bottom(4)
        .build();
    position_group.add(&position_label);

    controls.append(&position_group);

    // --- Advanced options ---
    let advanced_group = adw::PreferencesGroup::builder()
        .title("Advanced")
        .build();

    let advanced_expander = adw::ExpanderRow::builder()
        .title("Advanced Options")
        .subtitle("Color, opacity, rotation, tiling, margin, scale")
        .show_enable_switch(false)
        .expanded(state.is_section_expanded("watermark-advanced"))
        .build();

    {
        let st = state.clone();
        advanced_expander.connect_expanded_notify(move |row| {
            st.set_section_expanded("watermark-advanced", row.is_expanded());
        });
    }

    // Text color picker
    let color_row = adw::ActionRow::builder()
        .title("Text Color")
        .subtitle("Color of the watermark text")
        .build();

    let initial_color = gtk::gdk::RGBA::new(
        cfg.watermark_color[0] as f32 / 255.0,
        cfg.watermark_color[1] as f32 / 255.0,
        cfg.watermark_color[2] as f32 / 255.0,
        cfg.watermark_color[3] as f32 / 255.0,
    );
    let color_dialog = gtk::ColorDialog::builder()
        .with_alpha(true)
        .title("Watermark Text Color")
        .build();
    let color_button = gtk::ColorDialogButton::builder()
        .dialog(&color_dialog)
        .rgba(&initial_color)
        .valign(gtk::Align::Center)
        .build();
    color_button.update_property(&[
        gtk::accessible::Property::Label("Choose watermark text color"),
    ]);
    color_row.add_suffix(&color_button);

    // Opacity slider + reset
    let opacity_row = adw::ActionRow::builder()
        .title("Opacity")
        .subtitle(&format!("{}%", (cfg.watermark_opacity * 100.0).round() as i32))
        .build();
    let opacity_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, 0.0, 100.0, 1.0);
    opacity_scale.set_value((cfg.watermark_opacity * 100.0) as f64);
    opacity_scale.set_draw_value(false);
    opacity_scale.set_hexpand(false);
    opacity_scale.set_valign(gtk::Align::Center);
    opacity_scale.set_width_request(180);
    opacity_scale.update_property(&[
        gtk::accessible::Property::Label("Watermark opacity, 0 to 100 percent"),
    ]);
    let opacity_reset = gtk::Button::builder()
        .icon_name("edit-undo-symbolic")
        .valign(gtk::Align::Center)
        .tooltip_text("Reset to 50%")
        .has_frame(false)
        .build();
    opacity_reset.update_property(&[
        gtk::accessible::Property::Label("Reset opacity to 50%"),
    ]);
    opacity_reset.set_sensitive((cfg.watermark_opacity - 0.5).abs() > 0.01);
    opacity_row.add_suffix(&opacity_scale);
    opacity_row.add_suffix(&opacity_reset);

    // Rotation slider + reset (-180 to +180)
    let rotation_row = adw::ActionRow::builder()
        .title("Rotation")
        .subtitle(&format!("{} degrees", cfg.watermark_rotation))
        .build();
    let rotation_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, -180.0, 180.0, 1.0);
    rotation_scale.set_value(cfg.watermark_rotation as f64);
    rotation_scale.set_draw_value(false);
    rotation_scale.set_hexpand(false);
    rotation_scale.set_valign(gtk::Align::Center);
    rotation_scale.set_width_request(180);
    rotation_scale.update_property(&[
        gtk::accessible::Property::Label("Watermark rotation, -180 to +180 degrees"),
    ]);
    let rotation_reset = gtk::Button::builder()
        .icon_name("edit-undo-symbolic")
        .valign(gtk::Align::Center)
        .tooltip_text("Reset to 0 degrees")
        .has_frame(false)
        .build();
    rotation_reset.update_property(&[
        gtk::accessible::Property::Label("Reset rotation to 0 degrees"),
    ]);
    rotation_reset.set_sensitive(cfg.watermark_rotation != 0);
    rotation_row.add_suffix(&rotation_scale);
    rotation_row.add_suffix(&rotation_reset);

    // Tiled toggle
    let tiled_row = adw::SwitchRow::builder()
        .title("Tiled / Repeated")
        .subtitle("Repeat watermark across the entire image")
        .active(cfg.watermark_tiled)
        .tooltip_text("Repeat the watermark in a grid pattern across the entire image")
        .build();

    // Margin slider + reset
    let margin_row = adw::ActionRow::builder()
        .title("Margin from Edges")
        .subtitle(&format!("{} px", cfg.watermark_margin))
        .build();
    let margin_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, 0.0, 200.0, 1.0);
    margin_scale.set_value(cfg.watermark_margin as f64);
    margin_scale.set_draw_value(false);
    margin_scale.set_hexpand(false);
    margin_scale.set_valign(gtk::Align::Center);
    margin_scale.set_width_request(180);
    margin_scale.update_property(&[
        gtk::accessible::Property::Label("Watermark margin from edges, 0 to 200 pixels"),
    ]);
    let margin_reset = gtk::Button::builder()
        .icon_name("edit-undo-symbolic")
        .valign(gtk::Align::Center)
        .tooltip_text("Reset to 10 px")
        .has_frame(false)
        .build();
    margin_reset.update_property(&[
        gtk::accessible::Property::Label("Reset margin to 10 pixels"),
    ]);
    margin_reset.set_sensitive(cfg.watermark_margin != 10);
    margin_row.add_suffix(&margin_scale);
    margin_row.add_suffix(&margin_reset);

    // Scale slider + reset (only relevant for image watermarks)
    let scale_row = adw::ActionRow::builder()
        .title("Scale (% of image)")
        .subtitle(&format!("{}%", cfg.watermark_scale.round() as i32))
        .visible(cfg.watermark_use_image)
        .build();
    let scale_scale = gtk::Scale::with_range(gtk::Orientation::Horizontal, 1.0, 100.0, 1.0);
    scale_scale.set_value(cfg.watermark_scale as f64);
    scale_scale.set_draw_value(false);
    scale_scale.set_hexpand(false);
    scale_scale.set_valign(gtk::Align::Center);
    scale_scale.set_width_request(180);
    scale_scale.update_property(&[
        gtk::accessible::Property::Label("Watermark scale, 1 to 100 percent of image"),
    ]);
    let scale_reset = gtk::Button::builder()
        .icon_name("edit-undo-symbolic")
        .valign(gtk::Align::Center)
        .tooltip_text("Reset to 20%")
        .has_frame(false)
        .build();
    scale_reset.update_property(&[
        gtk::accessible::Property::Label("Reset scale to 20%"),
    ]);
    scale_reset.set_sensitive((cfg.watermark_scale - 20.0).abs() > 0.5);
    scale_row.add_suffix(&scale_scale);
    scale_row.add_suffix(&scale_reset);

    advanced_expander.add_row(&color_row);
    advanced_expander.add_row(&opacity_row);
    advanced_expander.add_row(&rotation_row);
    advanced_expander.add_row(&tiled_row);
    advanced_expander.add_row(&margin_row);
    advanced_expander.add_row(&scale_row);

    advanced_group.add(&advanced_expander);
    controls.append(&advanced_group);

    // Scrollable controls
    let controls_scrolled = gtk::ScrolledWindow::builder()
        .hscrollbar_policy(gtk::PolicyType::Never)
        .vexpand(true)
        .width_request(360)
        .child(&controls)
        .build();

    // === Main layout: 60/40 side-by-side ===
    let main_box = gtk::Box::builder()
        .orientation(gtk::Orientation::Horizontal)
        .spacing(12)
        .margin_top(12)
        .margin_bottom(12)
        .margin_start(12)
        .margin_end(12)
        .vexpand(true)
        .build();

    preview_box.set_width_request(400);
    main_box.append(&preview_box);
    main_box.append(&controls_scrolled);
    outer.append(&main_box);

    // Preview state
    let preview_index: Rc<Cell<usize>> = Rc::new(Cell::new(0));

    drop(cfg);

    // === Preview update closure ===
    let preview_gen: Rc<Cell<u32>> = Rc::new(Cell::new(0));
    let update_preview = {
        let files = state.loaded_files.clone();
        let jc = state.job_config.clone();
        let pic = preview_picture.clone();
        let info = info_label.clone();
        let pidx = preview_index.clone();
        let bind_gen = preview_gen.clone();

        Rc::new(move || {
            let loaded = files.borrow();
            if loaded.is_empty() {
                info.set_label("No images loaded");
                pic.set_paintable(gtk::gdk::Paintable::NONE);
                return;
            }

            let idx = pidx.get().min(loaded.len().saturating_sub(1));
            pidx.set(idx);
            let path = loaded[idx].clone();
            let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("image");
            info.set_label(&format!("[{}/{}] {}", idx + 1, loaded.len(), name));

            let cfg = jc.borrow();
            let wm_text = cfg.watermark_text.clone();
            let wm_use_image = cfg.watermark_use_image;
            let wm_image_path = cfg.watermark_image_path.clone();
            let wm_position = cfg.watermark_position;
            let wm_opacity = cfg.watermark_opacity;
            let wm_font_size = cfg.watermark_font_size;
            let wm_color = cfg.watermark_color;
            let wm_font_family = cfg.watermark_font_family.clone();
            let wm_tiled = cfg.watermark_tiled;
            let wm_margin = cfg.watermark_margin;
            let wm_scale = cfg.watermark_scale;
            let wm_rotation = cfg.watermark_rotation;
            let wm_enabled = cfg.watermark_enabled;
            drop(cfg);

            let my_gen = bind_gen.get().wrapping_add(1);
            bind_gen.set(my_gen);
            let gen_check = bind_gen.clone();

            let pic = pic.clone();
            let (tx, rx) = std::sync::mpsc::channel::<Option<Vec<u8>>>();
            std::thread::spawn(move || {
                let result = (|| -> Option<Vec<u8>> {
                    let img = image::open(&path).ok()?;
                    let img = img.resize(1024, 1024, image::imageops::FilterType::Triangle);

                    let img = if wm_enabled {
                        let position = match wm_position {
                            0 => pixstrip_core::operations::WatermarkPosition::TopLeft,
                            1 => pixstrip_core::operations::WatermarkPosition::TopCenter,
                            2 => pixstrip_core::operations::WatermarkPosition::TopRight,
                            3 => pixstrip_core::operations::WatermarkPosition::MiddleLeft,
                            4 => pixstrip_core::operations::WatermarkPosition::Center,
                            5 => pixstrip_core::operations::WatermarkPosition::MiddleRight,
                            6 => pixstrip_core::operations::WatermarkPosition::BottomLeft,
                            7 => pixstrip_core::operations::WatermarkPosition::BottomCenter,
                            _ => pixstrip_core::operations::WatermarkPosition::BottomRight,
                        };
                        let rotation = if wm_rotation != 0 {
                            Some(pixstrip_core::operations::WatermarkRotation::Custom(wm_rotation as f32))
                        } else {
                            None
                        };

                        let wm_config = if wm_use_image {
                            wm_image_path.as_ref().map(|p| {
                                pixstrip_core::operations::WatermarkConfig::Image {
                                    path: p.clone(),
                                    position,
                                    opacity: wm_opacity,
                                    scale: wm_scale / 100.0,
                                    rotation,
                                    tiled: wm_tiled,
                                    margin: wm_margin,
                                }
                            })
                        } else if !wm_text.is_empty() {
                            Some(pixstrip_core::operations::WatermarkConfig::Text {
                                text: wm_text,
                                position,
                                font_size: wm_font_size,
                                opacity: wm_opacity,
                                color: wm_color,
                                font_family: if wm_font_family.is_empty() { None } else { Some(wm_font_family) },
                                rotation,
                                tiled: wm_tiled,
                                margin: wm_margin,
                            })
                        } else {
                            None
                        };

                        if let Some(config) = wm_config {
                            pixstrip_core::operations::watermark::apply_watermark(img, &config).ok()?
                        } else {
                            img
                        }
                    } else {
                        img
                    };

                    let mut buf = Vec::new();
                    img.write_to(
                        &mut std::io::Cursor::new(&mut buf),
                        image::ImageFormat::Png,
                    ).ok()?;
                    Some(buf)
                })();
                let _ = tx.send(result);
            });

            glib::timeout_add_local(std::time::Duration::from_millis(100), move || {
                if gen_check.get() != my_gen {
                    return glib::ControlFlow::Break;
                }
                match rx.try_recv() {
                    Ok(Some(bytes)) => {
                        let gbytes = glib::Bytes::from(&bytes);
                        if let Ok(texture) = gtk::gdk::Texture::from_bytes(&gbytes) {
                            pic.set_paintable(Some(&texture));
                        }
                        glib::ControlFlow::Break
                    }
                    Ok(None) => glib::ControlFlow::Break,
                    Err(std::sync::mpsc::TryRecvError::Empty) => glib::ControlFlow::Continue,
                    Err(_) => glib::ControlFlow::Break,
                }
            });
        })
    };

    // Click-to-cycle on preview
    {
        let click = gtk::GestureClick::new();
        let pidx = preview_index.clone();
        let files = state.loaded_files.clone();
        let up = update_preview.clone();
        click.connect_released(move |_, _, _, _| {
            let loaded = files.borrow();
            if loaded.len() > 1 {
                let next = (pidx.get() + 1) % loaded.len();
                pidx.set(next);
                up();
            }
        });
        preview_picture.add_controller(click);
    }

    // Keyboard support for preview cycling (Space/Enter)
    {
        let key = gtk::EventControllerKey::new();
        let pidx = preview_index.clone();
        let files = state.loaded_files.clone();
        let up = update_preview.clone();
        key.connect_key_pressed(move |_, keyval, _, _| {
            if keyval == gtk::gdk::Key::space || keyval == gtk::gdk::Key::Return {
                let loaded = files.borrow();
                if loaded.len() > 1 {
                    let next = (pidx.get() + 1) % loaded.len();
                    pidx.set(next);
                    up();
                }
                return gtk::glib::Propagation::Stop;
            }
            gtk::glib::Propagation::Proceed
        });
        preview_picture.add_controller(key);
    }

    // === Wire signals ===

    // Enable toggle
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        enable_row.connect_active_notify(move |row| {
            jc.borrow_mut().watermark_enabled = row.is_active();
            up();
        });
    }

    // Type selector
    {
        let jc = state.job_config.clone();
        let text_group_c = text_group.clone();
        let image_group_c = image_group.clone();
        let scale_row_c = scale_row.clone();
        let up = update_preview.clone();
        type_row.connect_selected_notify(move |row| {
            let use_image = row.selected() == 1;
            jc.borrow_mut().watermark_use_image = use_image;
            text_group_c.set_visible(!use_image);
            image_group_c.set_visible(use_image);
            scale_row_c.set_visible(use_image);
            up();
        });
    }

    // Text entry (debounced to avoid preview on every keystroke)
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        let debounce_id: Rc<Cell<u32>> = Rc::new(Cell::new(0));
        text_row.connect_changed(move |row| {
            let text = row.text().to_string();
            jc.borrow_mut().watermark_text = text;
            let up = up.clone();
            let did = debounce_id.clone();
            let id = did.get().wrapping_add(1);
            did.set(id);
            glib::timeout_add_local_once(std::time::Duration::from_millis(300), move || {
                if did.get() == id {
                    up();
                }
            });
        });
    }

    // Font family
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        font_button.connect_font_desc_notify(move |btn| {
            if let Some(desc) = btn.font_desc() {
                if let Some(family) = desc.family() {
                    jc.borrow_mut().watermark_font_family = family.to_string();
                    up();
                }
            }
        });
    }

    // Font size
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        font_size_row.connect_value_notify(move |row| {
            jc.borrow_mut().watermark_font_size = row.value() as f32;
            up();
        });
    }

    // Position grid buttons
    for (i, btn) in buttons.iter().enumerate() {
        let jc = state.job_config.clone();
        let label = position_label.clone();
        let names = position_names;
        let all_buttons = buttons.clone();
        let up = update_preview.clone();
        btn.connect_toggled(move |b| {
            if b.is_active() {
                jc.borrow_mut().watermark_position = i as u32;
                label.set_label(names[i]);
                for (j, other) in all_buttons.iter().enumerate() {
                    let icon_name = if j == i {
                        "radio-checked-symbolic"
                    } else {
                        "radio-symbolic"
                    };
                    other.set_child(Some(&gtk::Image::from_icon_name(icon_name)));
                }
                up();
            }
        });
    }

    // Color picker
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        color_button.connect_rgba_notify(move |btn| {
            let c = btn.rgba();
            jc.borrow_mut().watermark_color = [
                (c.red() * 255.0) as u8,
                (c.green() * 255.0) as u8,
                (c.blue() * 255.0) as u8,
                (c.alpha() * 255.0) as u8,
            ];
            up();
        });
    }

    // Per-slider debounce counters (separate to avoid cross-slider cancellation)
    let opacity_debounce: Rc<Cell<u32>> = Rc::new(Cell::new(0));
    let rotation_debounce: Rc<Cell<u32>> = Rc::new(Cell::new(0));
    let margin_debounce: Rc<Cell<u32>> = Rc::new(Cell::new(0));
    let scale_debounce: Rc<Cell<u32>> = Rc::new(Cell::new(0));

    // Opacity slider
    {
        let jc = state.job_config.clone();
        let row = opacity_row.clone();
        let up = update_preview.clone();
        let rst = opacity_reset.clone();
        let did = opacity_debounce.clone();
        opacity_scale.connect_value_changed(move |scale| {
            let val = scale.value().round() as i32;
            let opacity = val as f32 / 100.0;
            jc.borrow_mut().watermark_opacity = opacity;
            row.set_subtitle(&format!("{}%", val));
            rst.set_sensitive(val != 50);
            let up = up.clone();
            let did = did.clone();
            let id = did.get().wrapping_add(1);
            did.set(id);
            glib::timeout_add_local_once(std::time::Duration::from_millis(150), move || {
                if did.get() == id { up(); }
            });
        });
    }
    {
        let scale = opacity_scale.clone();
        opacity_reset.connect_clicked(move |_| {
            scale.set_value(50.0);
        });
    }

    // Rotation slider
    {
        let jc = state.job_config.clone();
        let row = rotation_row.clone();
        let up = update_preview.clone();
        let rst = rotation_reset.clone();
        let did = rotation_debounce.clone();
        rotation_scale.connect_value_changed(move |scale| {
            let val = scale.value().round() as i32;
            jc.borrow_mut().watermark_rotation = val;
            row.set_subtitle(&format!("{} degrees", val));
            rst.set_sensitive(val != 0);
            let up = up.clone();
            let did = did.clone();
            let id = did.get().wrapping_add(1);
            did.set(id);
            glib::timeout_add_local_once(std::time::Duration::from_millis(150), move || {
                if did.get() == id { up(); }
            });
        });
    }
    {
        let scale = rotation_scale.clone();
        rotation_reset.connect_clicked(move |_| {
            scale.set_value(0.0);
        });
    }

    // Tiled toggle
    {
        let jc = state.job_config.clone();
        let up = update_preview.clone();
        tiled_row.connect_active_notify(move |row| {
            jc.borrow_mut().watermark_tiled = row.is_active();
            up();
        });
    }

    // Margin slider
    {
        let jc = state.job_config.clone();
        let row = margin_row.clone();
        let up = update_preview.clone();
        let rst = margin_reset.clone();
        let did = margin_debounce.clone();
        margin_scale.connect_value_changed(move |scale| {
            let val = scale.value().round() as i32;
            jc.borrow_mut().watermark_margin = val as u32;
            row.set_subtitle(&format!("{} px", val));
            rst.set_sensitive(val != 10);
            let up = up.clone();
            let did = did.clone();
            let id = did.get().wrapping_add(1);
            did.set(id);
            glib::timeout_add_local_once(std::time::Duration::from_millis(150), move || {
                if did.get() == id { up(); }
            });
        });
    }
    {
        let scale = margin_scale.clone();
        margin_reset.connect_clicked(move |_| {
            scale.set_value(10.0);
        });
    }

    // Scale slider
    {
        let jc = state.job_config.clone();
        let row = scale_row.clone();
        let up = update_preview.clone();
        let rst = scale_reset.clone();
        let did = scale_debounce.clone();
        scale_scale.connect_value_changed(move |scale| {
            let val = scale.value().round() as i32;
            jc.borrow_mut().watermark_scale = val as f32;
            row.set_subtitle(&format!("{}%", val));
            rst.set_sensitive((val - 20).abs() > 0);
            let up = up.clone();
            let did = did.clone();
            let id = did.get().wrapping_add(1);
            did.set(id);
            glib::timeout_add_local_once(std::time::Duration::from_millis(150), move || {
                if did.get() == id { up(); }
            });
        });
    }
    {
        let scale = scale_scale.clone();
        scale_reset.connect_clicked(move |_| {
            scale.set_value(20.0);
        });
    }

    // Image chooser button
    {
        let jc = state.job_config.clone();
        let path_row = image_path_row.clone();
        let up = update_preview.clone();
        choose_image_button.connect_clicked(move |btn| {
            let jc = jc.clone();
            let path_row = path_row.clone();
            let up = up.clone();
            let dialog = gtk::FileDialog::builder()
                .title("Choose Watermark Image")
                .modal(true)
                .build();

            let filter = gtk::FileFilter::new();
            filter.set_name(Some("Images"));
            filter.add_mime_type("image/png");
            filter.add_mime_type("image/svg+xml");
            let filters = gtk::gio::ListStore::new::<gtk::FileFilter>();
            filters.append(&filter);
            dialog.set_filters(Some(&filters));

            if let Some(window) = btn.root().and_then(|r| r.downcast::<gtk::Window>().ok()) {
                dialog.open(Some(&window), gtk::gio::Cancellable::NONE, move |result| {
                    if let Ok(file) = result
                        && let Some(path) = file.path()
                    {
                        path_row.set_subtitle(&path.display().to_string());
                        jc.borrow_mut().watermark_image_path = Some(path);
                        up();
                    }
                });
            }
        });
    }

    let page = adw::NavigationPage::builder()
        .title("Watermark")
        .tag("step-watermark")
        .child(&outer)
        .build();

    // Sync enable toggle, refresh preview and sensitivity when navigating to this page
    {
        let up = update_preview.clone();
        let lf = state.loaded_files.clone();
        let ctrl = controls.clone();
        let jc = state.job_config.clone();
        let er = enable_row.clone();
        page.connect_map(move |_| {
            let enabled = jc.borrow().watermark_enabled;
            er.set_active(enabled);
            ctrl.set_sensitive(!lf.borrow().is_empty());
            up();
        });
    }

    page
}
