use {
    cfonts::{render, Options},
    crate::{
        config::{
            Color,
            ColorVec,
            Config,
            Font,
        },
        error::CclockError,
    },
};

const RESET          : &str = "\x1b[0m";
const BLACK          : &str = "\x1b[30m";
const RED            : &str = "\x1b[31m";
const GREEN          : &str = "\x1b[32m";
const YELLOW         : &str = "\x1b[33m";
const BLUE           : &str = "\x1b[34m";
const MAGENTA        : &str = "\x1b[35m";
const CYAN           : &str = "\x1b[36m";
const WHITE          : &str = "\x1b[37m";
const BRIGHT_BLACK   : &str = "\x1b[90m";
const BRIGHT_RED     : &str = "\x1b[91m";
const BRIGHT_GREEN   : &str = "\x1b[92m";
const BRIGHT_YELLOW  : &str = "\x1b[93m";
const BRIGHT_BLUE    : &str = "\x1b[94m";
const BRIGHT_MAGENTA : &str = "\x1b[95m";
const BRIGHT_CYAN    : &str = "\x1b[96m";
const BRIGHT_WHITE   : &str = "\x1b[97m";

pub fn version_string() -> String {
    format!("{CYAN}cclock {MAGENTA}{}{RESET}", env!("CARGO_PKG_VERSION"))
}

pub fn cclock_string() -> String {
    let cfg = Config::new(&Font::Tiny, &[Color::Candy]);
    let cclock = render(Options {
        text: String::from("cclock"),
        font: cfg.font.into(),
        spaceless: true,
        colors: ColorVec(cfg.color.to_owned()).into(),
        ..Options::default()
    });
    cclock.text
}

pub fn help_string() -> String {
    let cfg = Config::new(&Font::Console, &[Color::Candy]);

    let candy = render(Options {
        text: String::from("candy (yay)"),
        font: cfg.font.into(),
        spaceless: true,
        colors: ColorVec(cfg.color).into(),
        ..Options::default()
    });

    format!(
r##"
{cclock}
{version}
{BRIGHT_MAGENTA}
options:
{BRIGHT_BLUE}
      --format {BRIGHT_GREEN}<string> {BRIGHT_MAGENTA}[default: %I:%M]{WHITE}
          format the time strftime(3) style
{BRIGHT_BLUE}
  -c, --color {BRIGHT_GREEN}<string> {BRIGHT_MAGENTA}[default: system]{WHITE}
          give a clock some color
          you can use multiple colors for supported fonts
          see the {BRIGHT_BLUE}--font{WHITE} section for the list

          eg:
          cclock -f block -c red -c green

          possible values:{RESET}
          ■ system (terminal's foreground)
          {BLACK}■ black
          {RED}■ red
          {GREEN}■ green
          {YELLOW}■ yellow
          {BLUE}■ blue
          {MAGENTA}■ magenta
          {CYAN}■ cyan
          {WHITE}■ white
          {BRIGHT_BLACK}■ bright-black
          {BRIGHT_RED}■ bright-red
          {BRIGHT_GREEN}■ bright-green
          {BRIGHT_YELLOW}■ bright-yellow
          {BRIGHT_BLUE}■ bright-blue
          {BRIGHT_MAGENTA}■ bright-magenta
          {BRIGHT_CYAN}■ bright-cyan
          {BRIGHT_WHITE}■ bright-white
          {BRIGHT_BLACK}■ {candy}
{BRIGHT_BLUE}
  -f, --font {BRIGHT_GREEN}<string> {BRIGHT_MAGENTA}[default: block]{WHITE}
          set the font
          
          possible values:
          ■ block        {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ simpleblock  {BRIGHT_MAGENTA}[colors: 1]{WHITE}
          ■ 3d           {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ simple3d     {BRIGHT_MAGENTA}[colors: 1]{WHITE}
          ■ chrome       {BRIGHT_MAGENTA}[colors: 3]{WHITE}
          ■ huge         {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ shade        {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ slick        {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ grid         {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ pallet       {BRIGHT_MAGENTA}[colors: 2]{WHITE}
          ■ simple       {BRIGHT_MAGENTA}[colors: 1]{WHITE}
          ■ tiny         {BRIGHT_MAGENTA}[colors: 1]{WHITE}
          ■ console      {BRIGHT_MAGENTA}[colors: 1]{WHITE}
{BRIGHT_BLUE}
  -l, --list-fonts{WHITE}
          list and render all the available fonts
{BRIGHT_BLUE}
  -g, --gradient {BRIGHT_GREEN}<quoted hex>{WHITE}
          set an RBG gradient instead of terminal colors

          eg:
          cclock -f chrome -g "#ffaabb" -g "#ee22ff" ...
{BRIGHT_BLUE}
  -u, --utc-offset {BRIGHT_GREEN}<signed int>{WHITE}
          set the utc offset, otherwise use local time

          eg:
          cclock -u "-3600", cclock -u "+7200"
{BRIGHT_BLUE}
  -s, --screensaver{WHITE}
          screensaver mode
{BRIGHT_BLUE}
  -h, --help{WHITE}
          print this help message
{BRIGHT_BLUE}
  -v, --version{WHITE}
          print version
{RESET}
"##,
        cclock = cclock_string(),
        version = version_string(),
        candy = candy.text,
    )
}

#[derive(Debug)]
pub struct Args {
    pub format: String,
    pub colors: Vec<Color>,
    pub font: Font,
    pub gradient: Vec<String>,
    pub utc_offset: Option<i32>,
    pub screensaver: bool,
    pub version: bool,
    pub help: bool,
    pub list: bool,
}

pub fn parse_arguments() -> Result <Args, CclockError> {
    let mut args = pico_args::Arguments::from_env();

    let help = args.contains(["-h", "--help"]);
    let version = args.contains(["-v", "--version"]);
    let screensaver = args.contains(["-s", "--screensaver"]);
    let list = args.contains(["-l", "--list-fonts"]);

    let utc_offset = args.opt_value_from_str(["-u", "--utc-offset"])?;

    let gradient : Vec<String> = args
        .values_from_str(["-g", "--gradient"])?;

    let font = args
        .opt_value_from_fn(["-f", "--font"], Font::font_from_str)?
        .unwrap_or(Font::Block);

    let colors : Vec<Color> = args
        .values_from_fn(["-c", "--color"], Color::color_from_str)?;

    let format = args
        .value_from_str(["-t", "--format"])
        .unwrap_or(String::from("%I:%M"));

    Ok(Args {
        format,
        colors,
        font,
        gradient,
        utc_offset,
        screensaver,
        version,
        help,
        list,
    })
}
