//! Recon resource — web-grounded research swarm.

use futures::Stream;

use crate::client::Kranth;
use crate::errors::Result;
use crate::sse::stream_recon_events;
use crate::types::*;

pub struct ReconResource<'a> {
    pub(crate) client: &'a Kranth,
}

impl<'a> ReconResource<'a> {
    /// Start a new recon run.
    pub async fn create(&self, req: &CreateReconRequest) -> Result<CreateReconResponse> {
        self.client.post("/v1/recon", req, None).await
    }

    /// Start a new recon run with an idempotency key.
    pub async fn create_with_idempotency_key(
        &self,
        req: &CreateReconRequest,
        idempotency_key: &str,
    ) -> Result<CreateReconResponse> {
        self.client.post("/v1/recon", req, Some(idempotency_key)).await
    }

    /// Fetch detail for a completed (or in-flight) recon run.
    pub async fn get(&self, recon_id: &str) -> Result<ReconDetail> {
        self.client
            .get(&format!("/v1/recon/{recon_id}"), &[])
            .await
    }

    /// List all recon runs for the org.
    pub async fn list(&self) -> Result<Vec<ReconSummary>> {
        #[derive(serde::Deserialize)]
        struct Wrap {
            recons: Vec<ReconSummary>,
        }
        let w: Wrap = self.client.get("/v1/recon", &[]).await?;
        Ok(w.recons)
    }

    /// Fetch available recon tiers and their credit prices.
    pub async fn tiers(&self) -> Result<Vec<ReconTier>> {
        #[derive(serde::Deserialize)]
        struct Wrap {
            tiers: Vec<ReconTier>,
        }
        let w: Wrap = self.client.get("/v1/recon/tiers", &[]).await?;
        Ok(w.tiers)
    }

    /// Export a completed recon run (returns raw JSON from the API).
    pub async fn export(&self, recon_id: &str) -> Result<serde_json::Value> {
        self.client
            .get(&format!("/v1/recon/{recon_id}/export"), &[])
            .await
    }

    /// Subscribe to the SSE event stream for a recon run. Each item is a
    /// [`Result<ReconEvent>`]; the stream ends when the server closes the
    /// connection (typically after `recon.complete` or `recon.failed`).
    pub fn stream(&self, recon_id: &str) -> impl Stream<Item = Result<ReconEvent>> + 'a {
        stream_recon_events(self.client.clone(), recon_id.to_string())
    }
}
