//! The compliance-controls provider port.
//!
//! The mapping engine turns findings into compliance status against a corpus of
//! controls. That corpus is pluggable: the built-in OSCAL catalog by default, or
//! a tenant-owned RAG of atomic controls derived from laws
//! (`breakpilot-compliance`) when available. A [`ControlsProvider`] abstracts the
//! source so the mapping engine does not hardcode a catalog.

use crate::error::CoreError;
use crate::models::ComplianceFramework;

/// A control retrieved from a controls corpus.
#[derive(Debug, Clone)]
pub struct Control {
    /// Stable control identifier (e.g. an OSCAL control id or a RAG chunk id).
    pub id: String,
    /// The framework this control belongs to.
    pub framework: ComplianceFramework,
    /// Short human-readable title.
    pub title: String,
    /// The control text / requirement.
    pub text: String,
    /// Free-form source reference (catalog name, law citation, ...).
    pub source: Option<String>,
}

/// A query for relevant controls.
pub struct ControlQuery<'a> {
    /// Frameworks in scope for the target.
    pub frameworks: &'a [ComplianceFramework],
    /// Free-text describing what to map (a finding summary, a component, ...).
    pub context: &'a str,
    /// Maximum number of controls to return.
    pub limit: usize,
}

/// A source of compliance controls (built-in OSCAL catalog, breakpilot RAG, ...).
#[allow(async_fn_in_trait)]
pub trait ControlsProvider: Send + Sync {
    /// Stable identifier for this provider.
    fn name(&self) -> &str;

    /// Retrieve the controls most relevant to the query.
    async fn controls(&self, query: &ControlQuery<'_>) -> Result<Vec<Control>, CoreError>;
}
