use bevy::color::Color;

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum Cell {
    #[default]
    Closed,
    MarkedClosed,
    Yes,
    No,
    LockedYes,
    LockedNo,
}

impl Cell {

    pub fn locked(&self) -> bool {
        matches!(self, Self::LockedYes) || matches!(self, Self::LockedNo)
    }

    pub fn lock(&self) -> Self {
        match self {
            Self::Yes => Self::LockedYes,
            Self::No => Self::LockedNo,
            _ => *self,
        }
    }
}

impl From<bool> for Cell {
    fn from(value: bool) -> Self {
        if value {
            Cell::Yes
        } else {
            Cell::No
        }
    }
}

impl From<Cell> for bool {
    fn from(value: Cell) -> Self {
        matches!(value, Cell::Yes) || matches!(value, Cell::LockedYes)
    }
}

impl From<Cell> for Color {

    fn from(value: Cell) -> Self {
        match value {
            Cell::Closed => Color::WHITE,
            Cell::MarkedClosed => Color::srgb_u8(0xff, 0xff, 0x80),
            Cell::Yes => Color::srgb_u8(0x00, 0x00, 0xff),
            Cell::No => Color::srgb_u8(0x80, 0x80, 0x80),
            Cell::LockedYes => Color::srgb_u8(0x00, 0x00, 0xff),
            Cell::LockedNo => Color::srgb_u8(0x80, 0x80, 0x80),
        }
    }
}

impl ToString for Cell {

    fn to_string(&self) -> String {
        match self {
            Cell::Closed => "•",
            Cell::MarkedClosed => "░",
            Cell::Yes => "█",
            Cell::No => " ",
            Cell::LockedYes => "█",
            Cell::LockedNo => " ",
        }.to_string()
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn cell_lock() {
        assert!(!Cell::Closed.locked());
        assert!(!Cell::MarkedClosed.locked());
        assert!(!Cell::Yes.locked());
        assert!(!Cell::No.locked());
        assert!(Cell::LockedYes.locked());
        assert!(Cell::LockedNo.locked());
    }

    #[test]
    fn from_boolean() {
        let got: Cell = true.into();
        assert_eq!(Cell::Yes, got);
        let got: Cell = false.into();
        assert_eq!(Cell::No, got);
    }

    #[test]
    fn to_boolean() {
        let got: bool = Cell::Closed.into();
        assert!(!got);
        let got: bool = Cell::MarkedClosed.into();
        assert!(!got);
        let got: bool = Cell::Closed.into();
        assert!(!got);
        let got: bool = Cell::Yes.into();
        assert!(got);
        let got: bool = Cell::No.into();
        assert!(!got);
        let got: bool = Cell::LockedYes.into();
        assert!(got);
        let got: bool = Cell::LockedNo.into();
        assert!(!got);
    }
}
