use clap::Args;
use crossterm::style::{Color, Stylize};
use std::fmt::Write;

const LOG_GUIDE: &str = include_str!("../LOG_GUIDE.md");

#[derive(Args)]
pub struct LogArgs {
    #[arg(value_parser = parse_level)]
    pub level: LogLevel,

    pub message: Vec<String>,

    #[arg(long)]
    pub guide: bool,
}

#[derive(Clone)]
pub enum LogLevel {
    Info,
    Warn,
    Error,
    Debug,
}

fn parse_level(s: &str) -> Result<LogLevel, String> {
    match s.to_lowercase().as_str() {
        "info" => Ok(LogLevel::Info),
        "warn" | "warning" => Ok(LogLevel::Warn),
        "error" => Ok(LogLevel::Error),
        "debug" => Ok(LogLevel::Debug),
        _ => Err(format!("nivel inválido: {s}. Usa: info, warn, error, debug")),
    }
}

fn level_label(level: &LogLevel) -> &'static str {
    match level {
        LogLevel::Info => "INFO",
        LogLevel::Warn => "WARN",
        LogLevel::Error => "ERROR",
        LogLevel::Debug => "DEBUG",
    }
}

fn level_color(level: &LogLevel) -> Color {
    match level {
        LogLevel::Info => Color::Cyan,
        LogLevel::Warn => Color::Yellow,
        LogLevel::Error => Color::Red,
        LogLevel::Debug => Color::Rgb { r: 120, g: 120, b: 120 },
    }
}

pub fn run(args: LogArgs) {
    if args.guide {
        println!("{}", LOG_GUIDE);
        return;
    }

    let message = args.message.join(" ");

    let mut buf = String::new();

    let now = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
    write!(buf, "{}", now.to_string().with(Color::Rgb { r: 120, g: 120, b: 120 })).unwrap();
    write!(buf, "  ").unwrap();
    write!(buf, "{:5}", level_label(&args.level).with(level_color(&args.level))).unwrap();
    write!(buf, "  ").unwrap();
    write!(buf, "{}", message.with(Color::White)).unwrap();

    println!("{}", buf);
}
