//! Recovery domain logic — encrypted recovery bundle CRUD.

use std::sync::Arc;

use crate::storage::Store;

use super::types::DomainError;

/// Maximum recovery bundle size: 64 KiB.
const MAX_BUNDLE_SIZE: usize = 64 * 1024;

/// Default TTL for recovery bundles: 90 days.
pub const DEFAULT_TTL_SECS: u64 = 90 * 24 * 60 * 60;

/// Domain service for recovery bundle operations.
pub struct RecoveryService {
    pub store: Arc<dyn Store>,
}

impl RecoveryService {
    /// Store an encrypted recovery bundle.
    ///
    /// `token_hash` is the SHA-256 of a recovery token derived from the code.
    /// `bundle` is the encrypted blob (opaque to server).
    /// `ttl_secs` is the time-to-live; 0 uses the default (90 days).
    pub fn store_bundle(
        &self,
        token_hash: &[u8],
        bundle: Vec<u8>,
        ttl_secs: u64,
    ) -> Result<(), DomainError> {
        if token_hash.len() != 32 {
            return Err(DomainError::BadParams(format!(
                "token_hash must be 32 bytes, got {}",
                token_hash.len()
            )));
        }
        if bundle.is_empty() {
            return Err(DomainError::BadParams("recovery bundle must not be empty".into()));
        }
        if bundle.len() > MAX_BUNDLE_SIZE {
            return Err(DomainError::BadParams(format!(
                "recovery bundle exceeds max size ({} > {MAX_BUNDLE_SIZE})",
                bundle.len()
            )));
        }

        let ttl = if ttl_secs == 0 { DEFAULT_TTL_SECS } else { ttl_secs };
        self.store.store_recovery_bundle(token_hash, bundle, ttl)?;
        Ok(())
    }

    /// Fetch an encrypted recovery bundle by token_hash.
    pub fn fetch_bundle(&self, token_hash: &[u8]) -> Result<Option<Vec<u8>>, DomainError> {
        if token_hash.len() != 32 {
            return Err(DomainError::BadParams(format!(
                "token_hash must be 32 bytes, got {}",
                token_hash.len()
            )));
        }
        let bundle = self.store.get_recovery_bundle(token_hash)?;
        Ok(bundle)
    }

    /// Delete an encrypted recovery bundle by token_hash.
    pub fn delete_bundle(&self, token_hash: &[u8]) -> Result<bool, DomainError> {
        if token_hash.len() != 32 {
            return Err(DomainError::BadParams(format!(
                "token_hash must be 32 bytes, got {}",
                token_hash.len()
            )));
        }
        let deleted = self.store.delete_recovery_bundle(token_hash)?;
        Ok(deleted)
    }
}
