use std::fmt::Display;

#[derive(Debug, Clone, Copy)]
pub(crate) enum RegisterOperation {
    Right,
    Left,
    Add,
    Subtract,
}

#[derive(Debug, Clone, Copy)]
pub(crate) enum Operation {
    Register(RegisterOperation),
    Result,
    Take,
    Jump,
}

impl Operation {
    pub fn try_from_char(char: char) -> Option<Operation> {
        match char {
            '>' => Some(Operation::Register(RegisterOperation::Right)),
            '<' => Some(Operation::Register(RegisterOperation::Left)),
            'v' => Some(Operation::Take),
            '+' => Some(Operation::Register(RegisterOperation::Add)),
            '-' => Some(Operation::Register(RegisterOperation::Subtract)),
            'n' => Some(Operation::Jump),
            '=' => Some(Operation::Result),
            _ => None,
        }
    }

    pub fn to_char(self) -> char {
        match self {
            Operation::Register(RegisterOperation::Right) => '>',
            Operation::Register(RegisterOperation::Left) => '<',
            Operation::Take => 'v',
            Operation::Register(RegisterOperation::Add) => '+',
            Operation::Register(RegisterOperation::Subtract) => '-',
            Operation::Jump => 'n',
            Operation::Result => '=',
        }
    }

    pub fn to_u8(self) -> u8 {
        match self {
            Operation::Register(RegisterOperation::Right) => 0,
            Operation::Register(RegisterOperation::Left) => 1,
            Operation::Take => 2,
            Operation::Register(RegisterOperation::Add) => 3,
            Operation::Register(RegisterOperation::Subtract) => 4,
            Operation::Jump => 5,
            Operation::Result => 6,
        }
    }
    pub fn try_from_u8(value: u8) -> Option<Operation> {
        match value {
            0 => Some(Operation::Register(RegisterOperation::Right)),
            1 => Some(Operation::Register(RegisterOperation::Left)),
            2 => Some(Operation::Take),
            3 => Some(Operation::Register(RegisterOperation::Add)),
            4 => Some(Operation::Register(RegisterOperation::Subtract)),
            5 => Some(Operation::Jump),
            6 => Some(Operation::Result),
            _ => None,
        }
    }
}

impl Display for Operation {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Operation::Register(RegisterOperation::Right) => write!(f, "right"),
            Operation::Register(RegisterOperation::Left) => write!(f, "left"),
            Operation::Take => write!(f, "take"),
            Operation::Register(RegisterOperation::Add) => write!(f, "add"),
            Operation::Register(RegisterOperation::Subtract) => write!(f, "subtract"),
            Operation::Jump => write!(f, "jump"),
            Operation::Result => write!(f, "result"),
        }
    }
}