//! Synchronous (blocking) wrapper over the async [`Kranth`] client.
//!
//! Suitable for scripts, CLIs, and any context where you cannot or do not
//! want to run an async executor yourself.  Uses a single-threaded Tokio
//! runtime internally.
//!
//! ```no_run
//! use kranth::blocking::KranthBlocking;
//!
//! let client = KranthBlocking::new("kr_live_…").unwrap();
//!
//! let sim = client.sims_create(&kranth::CreateSimRequest {
//!     idea_text:       "Charge $49/mo for a Rust linter.".into(),
//!     persona_count:   25,
//!     model_id:        "claude-haiku-4-5".into(),
//!     training_opt_in: None,
//! }).unwrap();
//!
//! // Blocks until the sim finishes and returns every event as a Vec.
//! let events = client.sims_stream(&sim.sim_id).unwrap();
//! for ev in events {
//!     println!("{} {:?}", ev.kind, ev.data);
//! }
//! ```

use futures::{pin_mut, StreamExt};

use crate::errors::{Error, Result};
use crate::types::*;
use crate::Kranth;

/// A blocking Kranth client.  Create once; reuse across calls.
pub struct KranthBlocking {
    inner: Kranth,
    rt: tokio::runtime::Runtime,
}

impl KranthBlocking {
    pub fn new(api_key: impl Into<String>) -> Result<Self> {
        let rt = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .map_err(|e| Error::Transport(format!("runtime init: {e}")))?;
        Ok(Self { inner: Kranth::new(api_key), rt })
    }

    pub fn with_base_url(api_key: impl Into<String>, base_url: impl Into<String>) -> Result<Self> {
        let rt = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .map_err(|e| Error::Transport(format!("runtime init: {e}")))?;
        let inner = Kranth::builder(api_key).base_url(base_url).build();
        Ok(Self { inner, rt })
    }

    // ─── me ──────────────────────────────────────────────────

    pub fn me(&self) -> Result<Me> {
        self.rt.block_on(self.inner.me())
    }

    // ─── sims ─────────────────────────────────────────────────

    pub fn sims_create(&self, req: &CreateSimRequest) -> Result<CreateSimResponse> {
        self.rt.block_on(self.inner.sims().create(req))
    }

    pub fn sims_create_idempotent(
        &self,
        req: &CreateSimRequest,
        idempotency_key: &str,
    ) -> Result<CreateSimResponse> {
        self.rt.block_on(
            self.inner.sims().create_with_idempotency_key(req, idempotency_key),
        )
    }

    pub fn sims_get(&self, sim_id: &str) -> Result<SimSummary> {
        self.rt.block_on(self.inner.sims().get(sim_id))
    }

    pub fn sims_list(&self, p: &ListSimsParams) -> Result<ListSimsResponse> {
        self.rt.block_on(self.inner.sims().list(p))
    }

    pub fn sims_cancel(&self, sim_id: &str) -> Result<serde_json::Value> {
        self.rt.block_on(self.inner.sims().cancel(sim_id))
    }

    /// Subscribe to a sim's event stream and block until the sim reaches a
    /// terminal state (`sim.complete` or `sim.failed`).  All events are
    /// buffered and returned as a `Vec`.
    ///
    /// For large sims (many personas, partial events) this can allocate a lot.
    /// Use the async [`crate::Kranth`] client and `sims().stream()` if you need
    /// back-pressure or incremental processing.
    pub fn sims_stream(&self, sim_id: &str) -> Result<Vec<SimEvent>> {
        let sim_id = sim_id.to_string();
        self.rt.block_on(async {
            let s = self.inner.sims().stream(&sim_id);
            pin_mut!(s);
            let mut events = Vec::new();
            loop {
                match s.next().await {
                    None => break,
                    Some(ev) => {
                        let done = ev.as_ref().map(|e| {
                            e.kind == "sim.complete" || e.kind == "sim.failed"
                        }).unwrap_or(false);
                        match ev {
                            Ok(e) => events.push(e),
                            Err(e) => return Err(e),
                        }
                        if done { break; }
                    }
                }
            }
            Ok(events)
        })
    }

    // ─── recon ───────────────────────────────────────────────

    pub fn recon_create(&self, req: &CreateReconRequest) -> Result<CreateReconResponse> {
        self.rt.block_on(self.inner.recon().create(req))
    }

    pub fn recon_get(&self, recon_id: &str) -> Result<ReconDetail> {
        self.rt.block_on(self.inner.recon().get(recon_id))
    }

    pub fn recon_list(&self) -> Result<Vec<ReconSummary>> {
        self.rt.block_on(self.inner.recon().list())
    }

    pub fn recon_tiers(&self) -> Result<Vec<ReconTier>> {
        self.rt.block_on(self.inner.recon().tiers())
    }

    pub fn recon_export(&self, recon_id: &str) -> Result<serde_json::Value> {
        self.rt.block_on(self.inner.recon().export(recon_id))
    }

    /// Subscribe to a recon run's event stream and block until it reaches a
    /// terminal state (`recon.complete` or `recon.failed`). All events are
    /// buffered and returned as a `Vec`.
    pub fn recon_stream(&self, recon_id: &str) -> Result<Vec<ReconEvent>> {
        let recon_id = recon_id.to_string();
        self.rt.block_on(async {
            let s = self.inner.recon().stream(&recon_id);
            pin_mut!(s);
            let mut events = Vec::new();
            loop {
                match s.next().await {
                    None => break,
                    Some(ev) => {
                        let done = ev.as_ref().map(|e| {
                            e.kind == "recon.complete" || e.kind == "recon.failed"
                        }).unwrap_or(false);
                        match ev {
                            Ok(e) => events.push(e),
                            Err(e) => return Err(e),
                        }
                        if done { break; }
                    }
                }
            }
            Ok(events)
        })
    }

    // ─── debates ─────────────────────────────────────────────

    pub fn debates_create(&self, req: &CreateDebateRequest) -> Result<DebateRow> {
        self.rt.block_on(self.inner.debates().create(req))
    }

    pub fn debates_get(&self, debate_id: &str) -> Result<DebateDetail> {
        self.rt.block_on(self.inner.debates().get(debate_id))
    }

    pub fn debates_list(&self) -> Result<ListDebatesResponse> {
        self.rt.block_on(self.inner.debates().list())
    }

    pub fn debates_turns(&self, debate_id: &str) -> Result<Vec<DebateTurn>> {
        self.rt.block_on(self.inner.debates().turns(debate_id))
    }

    pub fn debates_set_public(&self, debate_id: &str, public: bool) -> Result<DebateDetail> {
        self.rt.block_on(self.inner.debates().set_public(debate_id, public))
    }

    pub fn debates_cancel(&self, debate_id: &str) -> Result<serde_json::Value> {
        self.rt.block_on(self.inner.debates().cancel(debate_id))
    }

    pub fn debates_export(&self, debate_id: &str) -> Result<serde_json::Value> {
        self.rt.block_on(self.inner.debates().export(debate_id))
    }

    /// Subscribe to a debate's event stream and block until it reaches a
    /// terminal state (`debate.complete` or `debate.failed`). All events are
    /// buffered and returned as a `Vec`.
    pub fn debates_stream(&self, debate_id: &str) -> Result<Vec<DebateEvent>> {
        let debate_id = debate_id.to_string();
        self.rt.block_on(async {
            let s = self.inner.debates().stream(&debate_id);
            pin_mut!(s);
            let mut events = Vec::new();
            loop {
                match s.next().await {
                    None => break,
                    Some(ev) => {
                        let done = ev.as_ref().map(|e| {
                            e.kind == "debate.complete" || e.kind == "debate.failed"
                        }).unwrap_or(false);
                        match ev {
                            Ok(e) => events.push(e),
                            Err(e) => return Err(e),
                        }
                        if done { break; }
                    }
                }
            }
            Ok(events)
        })
    }

    // ─── api keys ────────────────────────────────────────────

    pub fn api_keys_list(&self) -> Result<Vec<ApiKey>> {
        self.rt.block_on(self.inner.api_keys().list())
    }

    pub fn api_keys_create(&self, name: &str, env: &str) -> Result<CreateApiKeyResponse> {
        self.rt.block_on(self.inner.api_keys().create(name, env))
    }

    pub fn api_keys_revoke(&self, id: &str) -> Result<()> {
        self.rt.block_on(self.inner.api_keys().revoke(id))
    }

    // ─── models ──────────────────────────────────────────────

    pub fn models_list(&self) -> Result<Vec<ModelInfo>> {
        self.rt.block_on(self.inner.models().list())
    }
}
