{
    const DEFAULT_EYE_RECORD_FPS: u32 = 30;

    #[derive(Default)]
    struct EyeRecordState {
        save_dir_override: Option<PathBuf>,
        timer: Option<glib::SourceId>,
        frame_dir: Option<PathBuf>,
        frame_writer_tx: Option<std::sync::mpsc::Sender<RecordFrameTask>>,
        finalize_rx: Option<std::sync::mpsc::Receiver<Result<PathBuf, String>>>,
        next_frame_index: u32,
    }

    enum RecordFrameTask {
        Frame {
            texture: gtk::gdk::Texture,
            frame_path: PathBuf,
        },
        Finish,
    }

    fn eye_slug(title: &str) -> &'static str {
        if title.to_ascii_lowercase().contains("left") {
            "left-eye"
        } else {
            "right-eye"
        }
    }

    fn timestamp_slug() -> String {
        if let Ok(now) = glib::DateTime::now_local()
            && let Ok(stamp) = now.format("%Y%m%d-%H%M%S")
        {
            return stamp.to_string();
        }
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default();
        format!("{}-{:03}", now.as_secs(), now.subsec_millis())
    }

    fn capture_day_slug() -> String {
        if let Ok(now) = glib::DateTime::now_local()
            && let Ok(stamp) = now.format("%Y-%m-%d")
        {
            return stamp.to_string();
        }
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default();
        format!("{}", now.as_secs() / 86_400)
    }

    fn expand_home_token(raw: &str) -> PathBuf {
        if raw.contains("$HOME") && let Some(home) = std::env::var_os("HOME") {
            return PathBuf::from(raw.replace("$HOME", &home.to_string_lossy()));
        }
        if let Some(rest) = raw.strip_prefix("~/")
            && let Some(home) = std::env::var_os("HOME")
        {
            return PathBuf::from(home).join(rest);
        }
        PathBuf::from(raw)
    }

    fn default_eye_capture_root() -> PathBuf {
        if let Some(raw) = std::env::var_os("XDG_PICTURES_DIR") {
            let path = expand_home_token(&raw.to_string_lossy());
            if !path.as_os_str().is_empty() {
                return path.join("lesavka");
            }
        }
        if let Some(home) = std::env::var_os("HOME") {
            return PathBuf::from(home).join("Pictures").join("lesavka");
        }
        if let Some(profile) = std::env::var_os("USERPROFILE") {
            return PathBuf::from(profile).join("Pictures").join("lesavka");
        }
        std::env::current_dir()
            .unwrap_or_else(|_| PathBuf::from("."))
            .join("lesavka")
    }

    fn ensure_eye_capture_root(override_dir: Option<&Path>) -> Result<PathBuf, String> {
        let root = override_dir
            .map(Path::to_path_buf)
            .unwrap_or_else(default_eye_capture_root);
        std::fs::create_dir_all(&root)
            .map_err(|err| format!("could not create {}: {err}", root.display()))?;
        Ok(root)
    }

    fn ensure_eye_capture_dir(override_dir: Option<&Path>, kind: &str) -> Result<PathBuf, String> {
        let root = ensure_eye_capture_root(override_dir)?;
        let dir = root.join(capture_day_slug()).join(kind);
        std::fs::create_dir_all(&dir)
            .map_err(|err| format!("could not create {}: {err}", dir.display()))?;
        Ok(dir)
    }

    fn unique_capture_path(root: &Path, stem: &str, ext: &str) -> PathBuf {
        let mut candidate = root.join(format!("{stem}.{ext}"));
        if !candidate.exists() {
            return candidate;
        }
        for idx in 1..1000 {
            candidate = root.join(format!("{stem}-{idx}.{ext}"));
            if !candidate.exists() {
                break;
            }
        }
        candidate
    }

    fn current_eye_texture(picture: &gtk::Picture) -> Result<gtk::gdk::Texture, String> {
        let paintable = picture
            .paintable()
            .ok_or_else(|| "no live frame is available yet".to_string())?;
        paintable
            .downcast::<gtk::gdk::Texture>()
            .map_err(|_| "the current frame is not directly exportable".to_string())
    }

    fn save_texture_png(texture: &gtk::gdk::Texture, output_path: &Path) -> Result<(), String> {
        texture
            .save_to_png(output_path)
            .map_err(|err| format!("could not write {}: {err}", output_path.display()))
    }

    fn recording_interval_ms(record_fps: u32) -> u64 {
        let fps = record_fps.max(1);
        (1000_u64 / fps as u64).max(1)
    }

    fn best_effort_recording_profile(
        state: &LauncherState,
        preview: Option<&LauncherPreview>,
        monitor_id: usize,
    ) -> (u32, u32) {
        let choice = state
            .display_capture_size_choice(monitor_id)
            .unwrap_or_else(|| state.capture_size_choice(monitor_id));
        let mut fps = if choice.fps == 0 {
            DEFAULT_EYE_RECORD_FPS
        } else {
            choice.fps.max(1)
        };
        if let Some(snapshot) =
            preview.and_then(|feed| feed.snapshot_metrics(monitor_id, PreviewSurface::Inline))
            && snapshot.server_fps.is_finite()
            && snapshot.server_fps >= 1.0
        {
            fps = snapshot.server_fps.round().clamp(1.0, 120.0) as u32;
        }
        let bitrate_kbit = choice.max_bitrate_kbit.max(800);
        (fps, bitrate_kbit)
    }

    fn queue_record_frame(state: &mut EyeRecordState, picture: &gtk::Picture) -> Result<(), String> {
        let frame_dir = state
            .frame_dir
            .as_ref()
            .ok_or_else(|| "recording session is not initialized".to_string())?
            .clone();
        let frame_writer_tx = state
            .frame_writer_tx
            .as_ref()
            .ok_or_else(|| "recording worker is not initialized".to_string())?
            .clone();
        let texture = current_eye_texture(picture)?;
        let frame_path = frame_dir.join(format!("frame-{:06}.png", state.next_frame_index));
        frame_writer_tx
            .send(RecordFrameTask::Frame {
                texture,
                frame_path,
            })
            .map_err(|_| "recording worker stopped unexpectedly".to_string())?;
        state.next_frame_index = state.next_frame_index.saturating_add(1);
        Ok(())
    }

    fn encode_recording(
        frame_dir: &Path,
        output_path: &Path,
        encode_fps: u32,
        encode_bitrate_kbit: u32,
    ) -> Result<(), String> {
        let frame_pattern = frame_dir.join("frame-%06d.png");
        let bitrate_arg = format!("{}k", encode_bitrate_kbit.max(800));
        let encode = Command::new("ffmpeg")
            .args([
                "-hide_banner",
                "-loglevel",
                "error",
                "-y",
                "-framerate",
                &encode_fps.max(1).to_string(),
                "-i",
                &frame_pattern.to_string_lossy(),
                "-c:v",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-r",
                &encode_fps.max(1).to_string(),
                "-b:v",
                &bitrate_arg,
                &output_path.to_string_lossy(),
            ])
            .status()
            .map_err(|err| format!("ffmpeg is unavailable: {err}"))?;

        if !encode.success() {
            return Err(format!(
                "ffmpeg failed while encoding {}; frame data is still in {}",
                output_path.display(),
                frame_dir.display()
            ));
        }
        Ok(())
    }

    fn run_recording_worker(
        frame_rx: std::sync::mpsc::Receiver<RecordFrameTask>,
        frame_dir: PathBuf,
        output_path: PathBuf,
        encode_fps: u32,
        encode_bitrate_kbit: u32,
    ) -> Result<PathBuf, String> {
        let mut captured_frames = 0_u32;
        while let Ok(task) = frame_rx.recv() {
            match task {
                RecordFrameTask::Frame {
                    texture,
                    frame_path,
                } => {
                    save_texture_png(&texture, &frame_path)?;
                    captured_frames = captured_frames.saturating_add(1);
                }
                RecordFrameTask::Finish => break,
            }
        }

        if captured_frames < 2 {
            let _ = std::fs::remove_dir_all(&frame_dir);
            return Err("need at least two captured frames to build a recording".to_string());
        }

        encode_recording(&frame_dir, &output_path, encode_fps, encode_bitrate_kbit)?;
        let _ = std::fs::remove_dir_all(&frame_dir);
        Ok(output_path)
    }
    for monitor_id in 0..2 {
        let pane = widgets.display_panes[monitor_id].clone();
        let widgets_for_ui = widgets.clone();
        let save_state = Rc::new(RefCell::new(EyeRecordState::default()));

        {
            let pane = pane.clone();
            let widgets = widgets_for_ui.clone();
            let save_state = Rc::clone(&save_state);
            let window_for_save = window.clone();
            pane.save_button.connect_clicked(move |_| {
                let chooser = gtk::FileChooserNative::new(
                    Some("Choose Eye Capture Folder"),
                    Some(&window_for_save),
                    gtk::FileChooserAction::SelectFolder,
                    Some("Select"),
                    Some("Cancel"),
                );
                chooser.set_modal(true);
                let save_state = Rc::clone(&save_state);
                let widgets = widgets.clone();
                let eye_name = pane.title.clone();
                chooser.connect_response(move |dialog, response| {
                    if response == gtk::ResponseType::Accept {
                        if let Some(folder) = dialog.file().and_then(|file| file.path()) {
                            save_state.borrow_mut().save_dir_override = Some(folder.clone());
                            widgets.status_label.set_text(&format!(
                                "{} saves now go to {}.",
                                eye_name,
                                folder.display()
                            ));
                        } else {
                            widgets.status_label.set_text(
                                "Capture folder selection did not return a filesystem path.",
                            );
                        }
                    }
                    dialog.destroy();
                });
                chooser.show();
            });
        }

        {
            let pane = pane.clone();
            let widgets = widgets_for_ui.clone();
            let save_state = Rc::clone(&save_state);
            pane.clip_button.connect_clicked(move |_| {
                let root = {
                    let borrowed = save_state.borrow();
                    match ensure_eye_capture_dir(borrowed.save_dir_override.as_deref(), "clips") {
                        Ok(path) => path,
                        Err(err) => {
                            widgets
                                .status_label
                                .set_text(&format!("Could not prepare capture folder: {err}"));
                            return;
                        }
                    }
                };

                let stem = format!("{}-clip-{}", eye_slug(&pane.title), timestamp_slug());
                let clip_path = unique_capture_path(&root, &stem, "png");
                match current_eye_texture(&pane.picture)
                    .and_then(|texture| save_texture_png(&texture, &clip_path))
                {
                    Ok(()) => {
                        widgets.status_label.set_text(&format!(
                            "{} clip saved to {}.",
                            pane.title,
                            clip_path.display()
                        ));
                    }
                    Err(err) => {
                        widgets
                            .status_label
                            .set_text(&format!("{} clip failed: {err}", pane.title));
                    }
                }
            });
        }

        {
            let pane = pane.clone();
            let widgets = widgets_for_ui.clone();
            let save_state = Rc::clone(&save_state);
            let state = Rc::clone(&state);
            let preview = preview.clone();
            let record_button = pane.record_button.clone();
            record_button.connect_clicked(move |button| {
                if save_state.borrow().timer.is_some() {
                    button.remove_css_class("recording-active");
                    let finalize_rx = {
                        let mut state = save_state.borrow_mut();
                        if let Some(timer) = state.timer.take() {
                            timer.remove();
                        }
                        if let Some(frame_writer_tx) = state.frame_writer_tx.take() {
                            let _ = frame_writer_tx.send(RecordFrameTask::Finish);
                        }
                        state.next_frame_index = 0;
                        state.frame_dir = None;
                        state.finalize_rx.take()
                    };
                    let Some(finalize_rx) = finalize_rx else {
                        button.set_label("Record");
                        widgets.status_label.set_text(&format!(
                            "{} recording stop failed: recording worker state was missing.",
                            pane.title
                        ));
                        return;
                    };

                    button.set_sensitive(false);
                    button.set_label("Finishing...");
                    let button = button.clone();
                    let widgets = widgets.clone();
                    let pane_title = pane.title.clone();
                    glib::timeout_add_local(Duration::from_millis(100), move || match finalize_rx
                        .try_recv()
                    {
                        Ok(Ok(output)) => {
                            button.set_sensitive(true);
                            button.remove_css_class("recording-active");
                            button.set_label("Record");
                            widgets.status_label.set_text(&format!(
                                "{} recording saved to {}.",
                                pane_title,
                                output.display()
                            ));
                            glib::ControlFlow::Break
                        }
                        Ok(Err(err)) => {
                            button.set_sensitive(true);
                            button.remove_css_class("recording-active");
                            button.set_label("Record");
                            widgets.status_label.set_text(&format!(
                                "{} recording stop failed: {err}",
                                pane_title,
                            ));
                            glib::ControlFlow::Break
                        }
                        Err(std::sync::mpsc::TryRecvError::Empty) => glib::ControlFlow::Continue,
                        Err(std::sync::mpsc::TryRecvError::Disconnected) => {
                            button.set_sensitive(true);
                            button.remove_css_class("recording-active");
                            button.set_label("Record");
                            widgets.status_label.set_text(&format!(
                                "{} recording stop failed: recording worker disconnected.",
                                pane_title
                            ));
                            glib::ControlFlow::Break
                        }
                    });
                    return;
                }

                let (record_fps, record_bitrate_kbit) = {
                    let state = state.borrow();
                    best_effort_recording_profile(&state, preview.as_deref(), monitor_id)
                };
                if let Err(err) = current_eye_texture(&pane.picture) {
                    widgets.status_label.set_text(&format!(
                        "{} recording needs a live frame first: {err}",
                        pane.title
                    ));
                    return;
                }
                let root = {
                    let borrowed = save_state.borrow();
                    match ensure_eye_capture_dir(borrowed.save_dir_override.as_deref(), "recordings") {
                        Ok(path) => path,
                        Err(err) => {
                            widgets
                                .status_label
                                .set_text(&format!("Could not prepare capture folder: {err}"));
                            return;
                        }
                    }
                };

                let recording_stem = format!("{}-record-{}", eye_slug(&pane.title), timestamp_slug());
                let output_path = unique_capture_path(&root, &recording_stem, "mp4");
                let frame_dir = root.join(format!("{}.frames", recording_stem));
                if let Err(err) = std::fs::create_dir_all(&frame_dir) {
                    widgets.status_label.set_text(&format!(
                        "{} record failed creating frame cache {}: {err}",
                        pane.title,
                        frame_dir.display()
                    ));
                    return;
                }

                let (frame_tx, frame_rx) = std::sync::mpsc::channel::<RecordFrameTask>();
                let (result_tx, result_rx) = std::sync::mpsc::channel::<Result<PathBuf, String>>();
                let frame_dir_worker = frame_dir.clone();
                let output_path_worker = output_path.clone();
                std::thread::spawn(move || {
                    let result = run_recording_worker(
                        frame_rx,
                        frame_dir_worker,
                        output_path_worker,
                        record_fps,
                        record_bitrate_kbit,
                    );
                    let _ = result_tx.send(result);
                });

                {
                    let mut state = save_state.borrow_mut();
                    state.frame_dir = Some(frame_dir);
                    state.frame_writer_tx = Some(frame_tx);
                    state.finalize_rx = Some(result_rx);
                    state.next_frame_index = 0;
                }

                let pane_for_tick = pane.clone();
                let widgets_for_tick = widgets.clone();
                let save_state_for_tick = Rc::clone(&save_state);
                let button_for_tick = button.clone();
                let timer = glib::timeout_add_local(
                    Duration::from_millis(recording_interval_ms(record_fps)),
                    move || {
                        let mut state = save_state_for_tick.borrow_mut();
                        if state.frame_dir.is_none() {
                            return glib::ControlFlow::Break;
                        }
                        if let Err(err) = queue_record_frame(&mut state, &pane_for_tick.picture) {
                            if let Some(frame_writer_tx) = state.frame_writer_tx.take() {
                                let _ = frame_writer_tx.send(RecordFrameTask::Finish);
                            }
                            state.timer = None;
                            state.next_frame_index = 0;
                            state.frame_dir = None;
                            state.finalize_rx = None;
                            button_for_tick.remove_css_class("recording-active");
                            button_for_tick.set_sensitive(true);
                            button_for_tick.set_label("Record");
                            widgets_for_tick.status_label.set_text(&format!(
                                "{} recording frame skipped: {err}",
                                pane_for_tick.title
                            ));
                            return glib::ControlFlow::Break;
                        }
                        glib::ControlFlow::Continue
                    },
                );
                save_state.borrow_mut().timer = Some(timer);
                button.set_sensitive(true);
                button.add_css_class("recording-active");
                button.set_label("Stop");
                widgets.status_label.set_text(&format!(
                    "Recording {} at {} fps (~{} kbit)... press Stop to finish.",
                    pane.title, record_fps, record_bitrate_kbit
                ));
            });
        }
    }
}
