/*
 * Copyright 2025 Yubico AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use strum_macros::EnumIter;
use yubihsmrs::object::ObjectCapability;
use yubihsmrs::Session;
use crate::traits::command_traits::Command;
use crate::common::error::MgmError;
use crate::common::types::EXIT_LABEL;

#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter)]
pub enum DeviceCommand {
    GetRandom,
    BackupDevice,
    RestoreDevice,
    Reset,
    Exit,
}

impl Command for DeviceCommand {
    fn label(&self) -> &'static str {
        match self {
            Self::GetRandom => "Generate pseudo random number",
            Self::BackupDevice => "Backup device",
            Self::RestoreDevice => "Restore device",
            Self::Reset => "Reset device",
            Self::Exit => EXIT_LABEL,
        }
    }

    fn description(&self) -> &'static str {
        match self {
            Self::GetRandom => "Get pseudo random bytes generated by the YubiHSM",
            Self::BackupDevice => "Exports all exportable objects under wrap",
            Self::RestoreDevice => "Reads all files ending with .yhw in a specified directory and imports the wrapped objects",
            Self::Reset => "Restores the YubiHSM to factory default settings. All data will be deleted from the device and cannot be recovered. Attestation key will not be overwritten",
            Self::Exit => "",
        }
    }

    fn required_capabilities(&self) -> &'static [ObjectCapability] {
        match self {
            Self::GetRandom => &[ObjectCapability::GetPseudoRandom],
            Self::BackupDevice => &[ObjectCapability::ExportWrapped],
            Self::RestoreDevice => &[ObjectCapability::ImportWrapped],
            Self::Reset => &[ObjectCapability::ResetDevice],
            Self::Exit => &[],
        }
    }
}

pub struct DeviceOperations;

impl DeviceOperations {

    pub fn get_random(session: &Session, num_bytes: usize) -> Result<Vec<u8>, MgmError> {
        Ok(session.get_random(num_bytes)?)
    }

    pub fn reset_device(session: &Session) -> Result<(), MgmError> {
        Ok(session.reset()?)
    }

}