use std::future::Future;
use std::pin::Pin;

use crate::error::CoreError;
use crate::models::dast::{DastFinding, DastTarget};
use crate::models::finding::Finding;
use crate::models::pentest::CodeContextHint;
use crate::models::sbom::SbomEntry;

/// Context passed to pentest tools during execution.
///
/// The HTTP client is not included here because `compliance-core` does not
/// depend on `reqwest`. Tools that need HTTP should hold their own client
/// or receive one via the `compliance-dast` orchestrator.
pub struct PentestToolContext {
    /// The DAST target being tested
    pub target: DastTarget,
    /// Session ID for this pentest run
    pub session_id: String,
    /// SAST findings for the linked repo (if any)
    pub sast_findings: Vec<Finding>,
    /// SBOM entries with known CVEs (if any)
    pub sbom_entries: Vec<SbomEntry>,
    /// Code knowledge graph hints mapping endpoints to source code
    pub code_context: Vec<CodeContextHint>,
    /// Rate limit (requests per second)
    pub rate_limit: u32,
    /// Whether destructive operations are allowed
    pub allow_destructive: bool,
}

/// Result from a pentest tool execution
pub struct PentestToolResult {
    /// Human-readable summary of what the tool found
    pub summary: String,
    /// DAST findings produced by this tool
    pub findings: Vec<DastFinding>,
    /// Tool-specific structured output data
    pub data: serde_json::Value,
}

/// A tool that the LLM pentest orchestrator can invoke.
///
/// Each tool represents a specific security testing capability
/// (e.g., SQL injection scanner, DNS checker, TLS analyzer).
/// Uses boxed futures for dyn-compatibility.
pub trait PentestTool: Send + Sync {
    /// Tool name for LLM tool_use (e.g., "sql_injection_scanner")
    fn name(&self) -> &str;

    /// Human-readable description for the LLM system prompt
    fn description(&self) -> &str;

    /// JSON Schema for the tool's input parameters
    fn input_schema(&self) -> serde_json::Value;

    /// Execute the tool with the given input
    fn execute<'a>(
        &'a self,
        input: serde_json::Value,
        context: &'a PentestToolContext,
    ) -> Pin<Box<dyn Future<Output = Result<PentestToolResult, CoreError>> + Send + 'a>>;
}
