use {
    std::cell::Cell,
    crate::error::CclockError,
};

pub struct Config {
    pub font: Font,
    pub color: Vec <Color>,
    pub height: Cell <usize>,
    pub width: Cell <usize>,
}

impl Config {
    pub fn new (font : &Font, color : &[Color]) -> Self {
        Self {
            font: font.to_owned(),
            color: color.to_owned(),
            width: Cell::new(0),
            height: Cell::new(0)
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Color {
    /// Uses the system font defined by your console
    System,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White,
    BrightBlack,
    BrightRed,
    BrightGreen,
    BrightYellow,
    BrightBlue,
    BrightMagenta,
    BrightCyan,
    BrightWhite,
    /// A color that randomizes it's colors from a set of bright candy-like color set.
    Candy,
    // /// `Rgb` allows you to use colors outside the traditional ansi16 color set.
    // /// It's value is the [`Rgb`] enum that has a single value called `Val`.
    // Rgb(Rgb),
}

impl From <Color> for cfonts::Colors {
    fn from (c : Color) -> Self {
        match c {
            Color::System        => cfonts::Colors::System,
            Color::Black         => cfonts::Colors::Black,
            Color::Red           => cfonts::Colors::Red,
            Color::Green         => cfonts::Colors::Green,
            Color::Yellow        => cfonts::Colors::Yellow,
            Color::Blue          => cfonts::Colors::Blue,
            Color::Magenta       => cfonts::Colors::Magenta,
            Color::Cyan          => cfonts::Colors::Cyan,
            Color::White         => cfonts::Colors::White,
            Color::BrightBlack   => cfonts::Colors::Gray,
            Color::BrightRed     => cfonts::Colors::RedBright,
            Color::BrightGreen   => cfonts::Colors::GreenBright,
            Color::BrightYellow  => cfonts::Colors::YellowBright,
            Color::BrightBlue    => cfonts::Colors::BlueBright,
            Color::BrightMagenta => cfonts::Colors::MagentaBright,
            Color::BrightCyan    => cfonts::Colors::CyanBright,
            Color::BrightWhite   => cfonts::Colors::WhiteBright,
            Color::Candy         => cfonts::Colors::Candy,
        }
    }
}

pub struct ColorVec (pub Vec <Color>);

impl From <ColorVec> for Vec <cfonts::Colors> {
    fn from (c: ColorVec) -> Self {
        c.0.iter().map(|c| (*c).into()).collect()
    }
}

impl Color {
    pub fn color_from_str (s : &str) -> Result <Color, CclockError> {
        let color = match s.to_lowercase().as_str() {
            "black"          => Color::Black,
            "red"            => Color::Red,
            "green"          => Color::Green,
            "yellow"         => Color::Yellow,
            "blue"           => Color::Blue,
            "magenta"        => Color::Magenta,
            "cyan"           => Color::Cyan,
            "white"          => Color::White,
            "bright-black"   => Color::BrightBlack,
            "bright-red"     => Color::BrightRed,
            "bright-green"   => Color::BrightGreen,
            "bright-yellow"  => Color::BrightYellow,
            "bright-blue"    => Color::BrightBlue,
            "bright-magenta" => Color::BrightMagenta,
            "bright-cyan"    => Color::BrightCyan,
            "bright-white"   => Color::BrightWhite,
            "candy"          => Color::Candy,
            _                => return Err(CclockError::UnknownColor),
        };
        Ok(color)
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Font {
    Console,
    Block,
    SimpleBlock,
    Simple,
    Big3d,
    Simple3d,
    Chrome,
    Huge,
    Shade,
    Slick,
    Grid,
    Pallet,
    Tiny,
}

impl From <Font> for cfonts::Fonts {
    fn from (f : Font) -> Self {
        match f {
            Font::Console     => cfonts::Fonts::FontConsole,
            Font::Block       => cfonts::Fonts::FontBlock,
            Font::SimpleBlock => cfonts::Fonts::FontSimpleBlock,
            Font::Simple      => cfonts::Fonts::FontSimple,
            Font::Big3d       => cfonts::Fonts::Font3d,
            Font::Simple3d    => cfonts::Fonts::FontSimple3d,
            Font::Chrome      => cfonts::Fonts::FontChrome,
            Font::Huge        => cfonts::Fonts::FontHuge,
            Font::Shade       => cfonts::Fonts::FontShade,
            Font::Slick       => cfonts::Fonts::FontSlick,
            Font::Grid        => cfonts::Fonts::FontGrid,
            Font::Pallet      => cfonts::Fonts::FontPallet,
            Font::Tiny        => cfonts::Fonts::FontTiny,
        }
    }
}

impl Font {
    pub const ENUMERATION : [Font ; 13] = [
        Font::Console,
        Font::Block,
        Font::SimpleBlock,
        Font::Simple,
        Font::Big3d,
        Font::Simple3d,
        Font::Chrome,
        Font::Huge,
        Font::Shade,
        Font::Slick,
        Font::Grid,
        Font::Pallet,
        Font::Tiny,
    ];

    pub fn font_from_str (s : &str) -> Result <Font, CclockError> {
        let font = match s.to_lowercase().as_str() {
            "console"        => Font::Console,
            "block"          => Font::Block,
            "simpleblock"    => Font::SimpleBlock,
            "simple"         => Font::Simple,
            "3d"             => Font::Big3d,
            "simple3d"       => Font::Simple3d,
            "chrome"         => Font::Chrome,
            "huge"           => Font::Huge,
            "shade"          => Font::Shade,
            "slick"          => Font::Slick,
            "grid"           => Font::Grid,
            "pallet"         => Font::Pallet,
            "tiny"           => Font::Tiny,
            _                => return Err(CclockError::UnknownFont),
        };
        Ok(font)
    }

    pub fn str_from_font (&self) -> &'static str {
        match self {
            Font::Console     => "console",
            Font::Block       => "block",
            Font::SimpleBlock => "simpleblock",
            Font::Simple      => "simple",
            Font::Big3d       => "3d",
            Font::Simple3d    => "simple3d",
            Font::Chrome      => "chrome",
            Font::Huge        => "huge",
            Font::Shade       => "shade",
            Font::Slick       => "slick",
            Font::Grid        => "grid",
            Font::Pallet      => "pallet",
            Font::Tiny        => "tiny",
        }
    }
}
