//! `AuthPolicy` defines an interface for entities external to the
//! ssh agent server to authorizing SSH agent operations.

use super::protocol::SIGNamespace;
use crate::{authorization::AuthError, crypto::PublicKey};

/// Session-bind context for an SSH sign request.
#[derive(Debug, Clone)]
pub struct SessionBindContext {
    /// Whether this is an agent forwarding request.
    pub is_forwarding: bool,
    /// SHA-256 fingerprint of the remote host's public key.
    pub host_fingerprint: String,
}

/// Connection-level context for an SSH sign request.
#[derive(Debug, Clone)]
pub struct ConnectionContext {
    /// Name of the process making the request. Often unavailable in sandboxed environments.
    pub process_name: Option<String>,
    /// Session-bind context. `None` when no session-bind extension was received.
    pub session_bind: Option<SessionBindContext>,
}

/// Request to sign data using an SSH key.
#[derive(Debug, Clone)]
pub struct SignRequest {
    /// The public key identifying which key to use for signing.
    pub public_key: PublicKey,
    /// The parsed representation of the sign request's SIG namespace. For authentications to a
    /// server, this is `None`.
    pub namespace: Option<SIGNamespace>,
    /// Connection-level context: peer process info and session-bind state.
    pub connection: ConnectionContext,
}

/// Authorization request for SSH agent operations.
#[derive(Debug, Clone)]
pub enum AuthRequest {
    /// Request to list available SSH keys
    List,
    /// Request to sign data with a specific key
    Sign(SignRequest),
}

/// Implementers of this policy use the context provided to authorize
/// or deny the ssh agent server operation that was requested.
#[async_trait::async_trait]
pub trait AuthPolicy: Send + Sync {
    /// Authorizes an SSH agent operation request.
    ///
    /// # Arguments
    ///
    /// * `request` - The authorization request to evaluate
    ///
    /// # Returns
    ///
    /// * `Ok(true)` - Operation is authorized
    /// * `Ok(false)` - Operation was denied
    ///
    /// # Errors
    ///
    /// * `AuthError` if an error occurred during authorization
    async fn authorize(&self, request: &AuthRequest) -> Result<bool, AuthError>;
}
