//! Stereo VU meter with dB-scaled level display.

use crate::theme;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Color;
use ratatui::widgets::Widget;

const DB_MIN: f32 = -48.0;
const DB_MAX: f32 = 3.0;
const DB_RANGE: f32 = DB_MAX - DB_MIN;

/// Stereo VU meter displaying left/right levels in dB.
pub struct VuMeter {
    left: f32,
    right: f32,
}

impl VuMeter {
    pub fn new(left: f32, right: f32) -> Self {
        Self { left, right }
    }

    fn amplitude_to_db(amp: f32) -> f32 {
        if amp <= 0.0 {
            DB_MIN
        } else {
            (20.0 * amp.log10()).clamp(DB_MIN, DB_MAX)
        }
    }

    fn db_to_normalized(db: f32) -> f32 {
        (db - DB_MIN) / DB_RANGE
    }

    fn row_to_color(row_position: f32, colors: &theme::ThemeColors) -> Color {
        if row_position > 0.9 {
            colors.meter.high
        } else if row_position > 0.75 {
            colors.meter.mid
        } else {
            colors.meter.low
        }
    }
}

impl Widget for VuMeter {
    fn render(self, area: Rect, buf: &mut Buffer) {
        if area.width < 3 || area.height == 0 {
            return;
        }

        let colors = theme::get();
        let height = area.height as usize;
        let half_width = area.width / 2;
        let gap = 1u16;

        let left_db = Self::amplitude_to_db(self.left);
        let right_db = Self::amplitude_to_db(self.right);
        let left_norm = Self::db_to_normalized(left_db);
        let right_norm = Self::db_to_normalized(right_db);

        let left_rows = (left_norm * height as f32).round() as usize;
        let right_rows = (right_norm * height as f32).round() as usize;

        for row in 0..height {
            let y = area.y + area.height - 1 - row as u16;
            let row_position = (row as f32 + 0.5) / height as f32;
            let color = Self::row_to_color(row_position, &colors);

            for col in 0..half_width.saturating_sub(gap) {
                let x = area.x + col;
                if row < left_rows {
                    buf[(x, y)].set_char(' ').set_bg(color);
                }
            }

            for col in 0..half_width.saturating_sub(gap) {
                let x = area.x + half_width + gap + col;
                if x < area.x + area.width && row < right_rows {
                    buf[(x, y)].set_char(' ').set_bg(color);
                }
            }
        }
    }
}
