use clap::ValueEnum;
use serde::Serialize;
use std::io::{self, Write};

#[derive(Debug, Clone, Copy, Default, ValueEnum)]
pub enum OutputFormat {
    #[default]
    Json,
    Table,
}

pub trait CliOutput: Serialize {
    fn print(&self, format: OutputFormat) -> io::Result<()> {
        match format {
            OutputFormat::Json => {
                let json = serde_json::to_string_pretty(self)?;
                println!("{}", json);
            }
            OutputFormat::Table => {
                self.print_table()?;
            }
        }
        Ok(())
    }

    fn print_table(&self) -> io::Result<()> {
        let json = serde_json::to_string_pretty(self)?;
        println!("{}", json);
        Ok(())
    }
}

pub fn print_json<T: Serialize>(value: &T) -> io::Result<()> {
    let json = serde_json::to_string_pretty(value)?;
    println!("{}", json);
    Ok(())
}

pub fn print_error(error: &str) {
    eprintln!("error: {}", error);
}

pub fn print_success(message: &str) {
    println!("{}", message);
}

pub fn print_table(headers: &[&str], rows: &[Vec<String>]) -> io::Result<()> {
    let mut widths: Vec<usize> = headers.iter().map(|h| h.len()).collect();

    for row in rows {
        for (i, cell) in row.iter().enumerate() {
            if i < widths.len() {
                widths[i] = widths[i].max(cell.len());
            }
        }
    }

    let separator: String = widths
        .iter()
        .map(|w| "-".repeat(*w + 2))
        .collect::<Vec<_>>()
        .join("+");

    let header_row: String = headers
        .iter()
        .enumerate()
        .map(|(i, h)| {
            format!(
                " {:width$} ",
                h,
                width = widths.get(i).copied().unwrap_or(0)
            )
        })
        .collect::<Vec<_>>()
        .join("|");

    println!("+{}+", separator);
    println!("|{}|", header_row);
    println!("+{}+", separator);

    for row in rows {
        let row_str: String = row
            .iter()
            .enumerate()
            .map(|(i, cell)| {
                format!(
                    " {:width$} ",
                    cell,
                    width = widths.get(i).copied().unwrap_or(0)
                )
            })
            .collect::<Vec<_>>()
            .join("|");
        println!("|{}|", row_str);
    }

    println!("+{}+", separator);
    io::stdout().flush()
}
