//! Chanora PoC API — `flutter_rust_bridge_hello`.
//!
//! Two flows are proven here:
//!   1. **Command:** `greet` — typed input → typed `Result<T, E>` DTO,
//!      including typed error mapping at the boundary.
//!   2. **Event stream:** `counterStream` — Rust pushes typed events to
//!      Dart via a `StreamSink`, observed in Dart as a `Stream<CounterTick>`.
//!
//! Together they satisfy the PoC exit criterion from
//! `docs/architecture/proof-of-concept-plan.md` §2:
//!     "Flutter can call Rust and receive event stream data."
//!
//! This is PoC code only. The Chanora DTO catalogue belongs to the
//! `chanora_bridge` crate; this PoC does not stand in for it.

use std::time::Duration;

use flutter_rust_bridge::frb;

use crate::frb_generated::StreamSink;

// -------- Command DTOs --------

#[derive(Debug, Clone)]
pub struct GreetResult {
    pub message: String,
    pub elapsed_micros: u64,
}

#[derive(Debug, Clone)]
pub enum GreetErrorKind {
    EmptyName,
}

/// Typed error DTO surfaced as a Dart exception by FRB.
#[derive(Debug, Clone, thiserror::Error)]
#[error("greet error: {kind:?}: {detail}")]
pub struct GreetError {
    pub kind: GreetErrorKind,
    pub detail: String,
}

// -------- Lifecycle --------

#[frb(init)]
pub fn init_app() {
    flutter_rust_bridge::setup_default_user_utils();
}

// -------- Command --------

/// Synchronous fallible command. Proves Dart → Rust call with a typed
/// `Result` DTO crossing the boundary.
#[frb(sync)]
pub fn greet(name: String) -> Result<GreetResult, GreetError> {
    let start = std::time::Instant::now();
    let trimmed = name.trim();
    if trimmed.is_empty() {
        return Err(GreetError {
            kind: GreetErrorKind::EmptyName,
            detail: "name must not be empty".into(),
        });
    }
    Ok(GreetResult {
        message: format!("Hello, {trimmed}! — greetings from Rust."),
        elapsed_micros: start.elapsed().as_micros() as u64,
    })
}

// -------- Event stream --------

#[derive(Debug, Clone)]
pub struct CounterTick {
    pub seq: u64,
    pub note: String,
}

/// Rust → Dart event stream.
/// `StreamSink` is provided in scope by `flutter_rust_bridge` glue;
/// the codegen wires it to a Dart `Stream<CounterTick>`.
pub async fn counter_stream(
    sink: StreamSink<CounterTick>,
    count: u32,
    interval_ms: u32,
) {
    let interval = Duration::from_millis(interval_ms.max(1) as u64);
    for i in 0..count {
        let tick = CounterTick {
            seq: i as u64,
            note: format!("tick {i}/{count}"),
        };
        if sink.add(tick).is_err() {
            break;
        }
        tokio::time::sleep(interval).await;
    }
}
