use std::sync::Arc;

use compliance_core::AgentConfig;

use crate::database::Database;
use crate::llm::LlmClient;
use crate::pipeline::orchestrator::PipelineOrchestrator;

#[derive(Clone)]
pub struct ComplianceAgent {
    pub config: AgentConfig,
    pub db: Database,
    pub llm: Arc<LlmClient>,
    pub http: reqwest::Client,
}

impl ComplianceAgent {
    pub fn new(config: AgentConfig, db: Database) -> Self {
        let llm = Arc::new(LlmClient::new(
            config.litellm_url.clone(),
            config.litellm_api_key.clone(),
            config.litellm_model.clone(),
            config.litellm_embed_model.clone(),
        ));
        Self {
            config,
            db,
            llm,
            http: reqwest::Client::new(),
        }
    }

    pub async fn run_scan(
        &self,
        repo_id: &str,
        trigger: compliance_core::models::ScanTrigger,
    ) -> Result<(), crate::error::AgentError> {
        let orchestrator = PipelineOrchestrator::new(
            self.config.clone(),
            self.db.clone(),
            self.llm.clone(),
            self.http.clone(),
        );
        orchestrator.run(repo_id, trigger).await
    }

    /// Run a PR review: scan the diff and post review comments.
    pub async fn run_pr_review(
        &self,
        repo_id: &str,
        pr_number: u64,
        base_sha: &str,
        head_sha: &str,
    ) -> Result<(), crate::error::AgentError> {
        let repo = self
            .db
            .repositories()
            .find_one(mongodb::bson::doc! {
                "_id": mongodb::bson::oid::ObjectId::parse_str(repo_id)
                    .map_err(|e| crate::error::AgentError::Other(e.to_string()))?
            })
            .await?
            .ok_or_else(|| {
                crate::error::AgentError::Other(format!("Repository {repo_id} not found"))
            })?;

        let orchestrator = PipelineOrchestrator::new(
            self.config.clone(),
            self.db.clone(),
            self.llm.clone(),
            self.http.clone(),
        );
        orchestrator
            .run_pr_review(&repo, repo_id, pr_number, base_sha, head_sha)
            .await
    }
}
