use aurora_core::{AuroraResult, Pipeline, Value};
fn ansi_hex(code: u8) -> String {
let r = ((code >> 5) & 7) as f64 / 7.0 * 255.0;
let g = ((code >> 2) & 7) as f64 / 7.0 * 255.0;
let b = (code & 3) as f64 / 3.0 * 255.0;
format!("#{:02x}{:02x}{:02x}", r as u8, g as u8, b as u8)
}
pub fn color_palette() -> AuroraResult<Pipeline> {
let mut rows: Vec<Vec<Value>> = Vec::new();
for i in 0..=255 {
let hex = ansi_hex(i);
let sample = format!("\x1b[48;5;{}m \x1b[0m", i);
rows.push(vec![
Value::Int(i as i64),
Value::String(sample),
Value::String(hex),
]);
}
Ok(Pipeline::table(
vec!["code".into(), "sample".into(), "hex".into()],
rows,
))
}
fn hex_to_rgb(hex: &str) -> Option<(u8, u8, u8)> {
let hex = hex.trim_start_matches('#');
if hex.len() != 6 { return None; }
let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
Some((r, g, b))
}
fn rgb_to_ansi(r: u8, g: u8, b: u8) -> u8 {
let r_idx = (r as f64 / 255.0 * 5.0).round() as u8;
let g_idx = (g as f64 / 255.0 * 5.0).round() as u8;
let b_idx = (b as f64 / 255.0 * 5.0).round() as u8;
16 + r_idx * 36 + g_idx * 6 + b_idx
}
pub fn color_hex(hex: &str) -> AuroraResult<Pipeline> {
let (r, g, b) = hex_to_rgb(hex).ok_or_else(|| {
aurora_core::AuroraError::InvalidInput(
format!("invalid hex color: {}", hex)
)
})?;
let ansi = rgb_to_ansi(r, g, b);
let mut record = std::collections::BTreeMap::new();
record.insert("hex".into(), Value::String(hex.into()));
record.insert("r".into(), Value::Int(r as i64));
record.insert("g".into(), Value::Int(g as i64));
record.insert("b".into(), Value::Int(b as i64));
record.insert("ansi_code".into(), Value::Int(ansi as i64));
Ok(Pipeline::single(Value::Record(record)))
}
pub fn color_rgb(r: u8, g: u8, b: u8) -> AuroraResult<Pipeline> {
let hex = format!("#{:02x}{:02x}{:02x}", r, g, b);
let ansi = rgb_to_ansi(r, g, b);
let mut record = std::collections::BTreeMap::new();
record.insert("hex".into(), Value::String(hex));
record.insert("r".into(), Value::Int(r as i64));
record.insert("g".into(), Value::Int(g as i64));
record.insert("b".into(), Value::Int(b as i64));
record.insert("ansi_code".into(), Value::Int(ansi as i64));
Ok(Pipeline::single(Value::Record(record)))
}