use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::Style;
use ratatui::Frame;

use crate::app::App;
use crate::theme;
use crate::widgets::{SampleBrowser, Waveform};

pub fn render(frame: &mut Frame, app: &App, area: Rect) {
    render_browser(frame, app, area);
}

fn render_browser(frame: &mut Frame, app: &App, area: Rect) {
    let state = match &app.sample_browser {
        Some(s) => s,
        None => return,
    };

    let [tree_area, preview_area] =
        Layout::vertical([Constraint::Fill(1), Constraint::Length(6)]).areas(area);

    let mut vh = tree_area.height.saturating_sub(2) as usize;
    if state.search_active || !state.search_query.is_empty() {
        vh = vh.saturating_sub(1);
    }
    state.visible_height.set(vh);

    let entries = state.entries();
    SampleBrowser::new(&entries, state.cursor)
        .scroll_offset(state.scroll_offset)
        .search(&state.search_query, state.search_active)
        .focused(true)
        .render(frame, tree_area);

    render_waveform_preview(frame, app, state, preview_area);
}

fn render_waveform_preview(
    frame: &mut Frame,
    app: &App,
    state: &crate::state::SampleBrowserState,
    area: Rect,
) {
    use ratatui::text::{Line, Span};
    use ratatui::widgets::Paragraph;
    use std::cell::RefCell;

    let sample = match state
        .sample_key()
        .and_then(|key| app.audio.sample_registry.as_ref()?.get(&key))
        .filter(|s| s.frame_count >= s.total_frames)
    {
        Some(s) => s,
        None => return,
    };

    thread_local! {
        static MONO_BUF: RefCell<Vec<f32>> = const { RefCell::new(Vec::new()) };
    }

    let [wave_area, info_area] =
        Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).areas(area);

    MONO_BUF.with(|buf| {
        let mut buf = buf.borrow_mut();
        let channels = sample.channels as usize;
        let frame_count = sample.frame_count as usize;
        buf.clear();
        buf.reserve(frame_count);
        for i in 0..frame_count {
            buf.push(sample.frames[i * channels]);
        }
        frame.render_widget(Waveform::new(&buf), wave_area);
    });

    let duration = sample.total_frames as f32 / app.audio.config.sample_rate;
    let ch_label = if sample.channels == 1 {
        "mono"
    } else {
        "stereo"
    };
    let info = Paragraph::new(Line::from(Span::styled(
        format!(" {duration:.1}s \u{00B7} {ch_label}"),
        Style::new().fg(theme::get().ui.text_dim),
    )));
    frame.render_widget(info, info_area);
}
