//! Color theme and style helpers for the Foxhunt TUI.
//!
//! All colors are derived from the Foxhunt brand: purple + cyan on dark navy.

use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::{Block, Borders};

// ---------------------------------------------------------------------------
// Brand palette
// ---------------------------------------------------------------------------

/// Dark navy background (#0F0F23).
pub const BG: Color = Color::Rgb(15, 15, 35);

/// Slightly lighter surface (#1A1A2E).
pub const SURFACE: Color = Color::Rgb(26, 26, 46);

/// Primary text -- light gray (#E0E0E0).
pub const TEXT: Color = Color::Rgb(224, 224, 224);

/// Primary accent -- purple (#8B5CF6).
pub const PRIMARY: Color = Color::Rgb(139, 92, 246);

/// Secondary accent -- cyan (#06B6D4).
pub const SECONDARY: Color = Color::Rgb(6, 182, 212);

/// Success -- green (#10B981).
pub const SUCCESS: Color = Color::Rgb(16, 185, 129);

/// Warning -- amber (#F59E0B).
pub const WARNING: Color = Color::Rgb(245, 158, 11);

/// Error -- red (#EF4444).
pub const ERROR: Color = Color::Rgb(239, 68, 68);

/// Muted text -- gray (#6B7280).
pub const MUTED: Color = Color::Rgb(107, 114, 128);

/// Border -- dim purple (#4C1D95).
pub const BORDER: Color = Color::Rgb(76, 29, 149);

/// Highlight -- bright cyan (#22D3EE).
pub const HIGHLIGHT: Color = Color::Rgb(34, 211, 238);

// ---------------------------------------------------------------------------
// Style helpers
// ---------------------------------------------------------------------------

/// Bold primary-colored text for titles.
pub fn title_style() -> Style {
    Style::default().fg(PRIMARY).add_modifier(Modifier::BOLD)
}

/// Dim purple border style.
pub fn border_style() -> Style {
    Style::default().fg(BORDER)
}

/// Green for healthy, red for unhealthy.
pub fn status_style(healthy: bool) -> Style {
    if healthy {
        Style::default().fg(SUCCESS)
    } else {
        Style::default().fg(ERROR)
    }
}

/// Header row style for tables -- secondary accent, bold.
pub fn header_style() -> Style {
    Style::default()
        .fg(SECONDARY)
        .add_modifier(Modifier::BOLD)
}

/// Standard bordered block with a purple title.
pub fn block(title: &str) -> Block<'_> {
    Block::default()
        .borders(Borders::ALL)
        .border_style(border_style())
        .title(title.to_owned())
        .title_style(title_style())
}

/// Muted text style.
pub fn muted_style() -> Style {
    Style::default().fg(MUTED)
}

/// Accent style for highlighted values.
pub fn accent_style() -> Style {
    Style::default().fg(HIGHLIGHT)
}

/// Warning style.
pub fn warning_style() -> Style {
    Style::default().fg(WARNING)
}

// ---------------------------------------------------------------------------
// Formatting helpers
// ---------------------------------------------------------------------------

/// Format a float as a dollar string with thousand separators and 2 decimal places.
/// Example: `format_usd(1_250_000.0)` => `"$1,250,000.00"`.
pub fn format_usd(value: f64) -> String {
    let abs = value.abs();
    let integer_part = abs as u64;
    let frac = abs - integer_part as f64;
    let int_str = format_u64_with_commas(integer_part);
    let sign = if value < 0.0 { "-" } else { "" };
    format!("{sign}${int_str}.{:02}", (frac * 100.0).round() as u64)
}

/// Format a float as a signed dollar string with thousand separators.
/// Example: `format_usd_signed(-4375.0)` => `"-$4,375.00"`.
pub fn format_usd_signed(value: f64) -> String {
    let abs = value.abs();
    let integer_part = abs as u64;
    let frac = abs - integer_part as f64;
    let int_str = format_u64_with_commas(integer_part);
    let sign = if value < 0.0 { "-" } else { "+" };
    format!("{sign}${int_str}.{:02}", (frac * 100.0).round() as u64)
}

/// Format a u64 with thousand separators.
fn format_u64_with_commas(n: u64) -> String {
    let s = n.to_string();
    let bytes = s.as_bytes();
    let len = bytes.len();
    #[allow(clippy::integer_division)]
    let cap = len + len / 3;
    let mut result = String::with_capacity(cap);
    for (i, &b) in bytes.iter().enumerate() {
        if i > 0 && (len - i) % 3 == 0 {
            result.push(',');
        }
        result.push(b as char);
    }
    result
}
