Skip to main content

allframe_core/router/
mod.rs

1//! # Protocol-Agnostic Router
2//!
3//! Write handlers once, expose them via REST, GraphQL, and gRPC.
4//!
5//! This is AllFrame's core differentiator - the same handler can serve
6//! multiple protocols without code changes.
7//!
8//! ## Quick Start
9//!
10//! ```rust
11//! use allframe_core::router::{Router, RestAdapter, GraphQLAdapter, GrpcAdapter};
12//!
13//! // Create router and register handlers
14//! let mut router = Router::new();
15//! router.register("get_user", || async {
16//!     r#"{"id": 42, "name": "Alice"}"#.to_string()
17//! });
18//!
19//! // Expose via REST
20//! let mut rest = RestAdapter::new();
21//! rest.route("GET", "/users/:id", "get_user");
22//!
23//! // Expose via GraphQL
24//! let mut graphql = GraphQLAdapter::new();
25//! graphql.query("user", "get_user");
26//!
27//! // Expose via gRPC
28//! let mut grpc = GrpcAdapter::new();
29//! grpc.unary("UserService", "GetUser", "get_user");
30//! ```
31//!
32//! ## Key Types
33//!
34//! - `Router` - Central handler registry
35//! - `RestAdapter` - REST protocol adapter
36//! - `GraphQLAdapter` - GraphQL protocol adapter
37//! - `GrpcAdapter` - gRPC protocol adapter
38//! - `ProtocolAdapter` - Trait for custom protocol adapters
39//!
40//! ## API Documentation
41//!
42//! Generate beautiful API documentation automatically:
43//!
44//! - `scalar_html` - Scalar UI for REST APIs (<50KB)
45//! - `graphiql_html` - GraphiQL playground for GraphQL
46//! - `grpc_explorer_html` - gRPC Explorer for gRPC services
47//! - `OpenApiGenerator` - OpenAPI 3.1 spec generation
48//!
49//! ## Configuration-Driven Protocol Selection
50//!
51//! Use TOML configuration to select protocols without code changes:
52//!
53//! ```toml
54//! [server]
55//! protocols = ["rest", "graphql", "grpc"]
56//!
57//! [server.rest]
58//! port = 8080
59//!
60//! [server.graphql]
61//! port = 8081
62//! ```
63
64use serde::de::DeserializeOwned;
65use serde::Serialize;
66use futures_core::Stream;
67use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
68
69pub mod adapter;
70pub mod builder;
71#[cfg(feature = "router")]
72pub mod config;
73pub mod contract;
74pub mod docs;
75pub mod graphiql;
76pub mod graphql;
77pub mod grpc;
78pub mod grpc_explorer;
79pub mod handler;
80pub mod metadata;
81pub mod method;
82pub mod openapi;
83pub mod rest;
84pub mod scalar;
85pub mod schema;
86pub mod ts_codegen;
87
88// Production adapters (optional features)
89#[cfg(feature = "router-graphql")]
90pub mod graphql_prod;
91#[cfg(feature = "router-grpc")]
92pub mod grpc_prod;
93
94pub use adapter::ProtocolAdapter;
95pub use builder::RouteBuilder;
96#[cfg(feature = "router")]
97pub use config::{GraphQLConfig, GrpcConfig, RestConfig, RouterConfig, ServerConfig};
98pub use contract::{
99    ContractTestConfig, ContractTestResult, ContractTestResults, ContractTestable, ContractTester,
100};
101pub use docs::DocsConfig;
102pub use graphiql::{graphiql_html, GraphiQLConfig, GraphiQLTheme};
103pub use graphql::{GraphQLAdapter, GraphQLOperation, OperationType};
104// Re-export production adapters when features are enabled
105#[cfg(feature = "router-graphql")]
106pub use graphql_prod::GraphQLProductionAdapter;
107pub use grpc::{GrpcAdapter, GrpcMethod, GrpcMethodType, GrpcRequest, GrpcStatus};
108pub use grpc_explorer::{grpc_explorer_html, GrpcExplorerConfig, GrpcExplorerTheme};
109#[cfg(feature = "router-grpc")]
110pub use grpc_prod::{protobuf, status, streaming, GrpcProductionAdapter, GrpcService};
111pub use handler::{
112    Handler, HandlerFn, HandlerWithArgs, HandlerWithState, HandlerWithStateOnly,
113    IntoHandlerResult, IntoStreamItem, Json, SharedStateMap, State, StreamError, StreamHandler,
114    StreamReceiver, StreamSender, StreamingHandlerFn, StreamingHandlerWithArgs,
115    StreamingHandlerWithState, StreamingHandlerWithStateOnly, DEFAULT_STREAM_CAPACITY,
116};
117pub use metadata::RouteMetadata;
118pub use method::Method;
119pub use openapi::{OpenApiGenerator, OpenApiServer};
120pub use rest::{RestAdapter, RestRequest, RestResponse, RestRoute};
121pub use scalar::{scalar_html, ScalarConfig, ScalarLayout, ScalarTheme};
122pub use schema::ToJsonSchema;
123pub use ts_codegen::{generate_ts_client, HandlerMeta, TsField, TsType};
124
125/// Drive a `Stream` to completion, forwarding items through a `StreamSender`.
126///
127/// Returns a JSON result: `"null"` on success, or a JSON error string if a
128/// serialization error occurred.
129async fn drive_stream<T, St>(stream: St, tx: &StreamSender) -> String
130where
131    T: IntoStreamItem,
132    St: Stream<Item = T> + Send,
133{
134    tokio::pin!(stream);
135    loop {
136        let next = std::future::poll_fn(|cx| stream.as_mut().poll_next(cx)).await;
137        match next {
138            Some(item) => match tx.send(item).await {
139                Ok(()) => {}
140                Err(StreamError::Closed) => break,
141                Err(StreamError::Serialize(e)) => {
142                    return serde_json::json!({"error": e}).to_string();
143                }
144            },
145            None => break,
146        }
147    }
148    "null".to_string()
149}
150
151/// Router manages handler registration and protocol adapters
152///
153/// The router allows you to register handlers once and expose them via
154/// multiple protocols based on configuration.
155pub struct Router {
156    handlers: HashMap<String, Box<dyn Handler>>,
157    streaming_handlers: HashMap<String, Box<dyn StreamHandler>>,
158    adapters: HashMap<String, Box<dyn ProtocolAdapter>>,
159    routes: Vec<RouteMetadata>,
160    states: SharedStateMap,
161    handler_metas: HashMap<String, HandlerMeta>,
162    #[cfg(feature = "router")]
163    #[allow(dead_code)]
164    config: Option<RouterConfig>,
165}
166
167impl Router {
168    /// Create a new router
169    pub fn new() -> Self {
170        Self {
171            handlers: HashMap::new(),
172            streaming_handlers: HashMap::new(),
173            adapters: HashMap::new(),
174            routes: Vec::new(),
175            states: Arc::new(std::sync::RwLock::new(HashMap::new())),
176            handler_metas: HashMap::new(),
177            #[cfg(feature = "router")]
178            config: None,
179        }
180    }
181
182    /// Create a new router with configuration
183    #[cfg(feature = "router")]
184    pub fn with_config(config: RouterConfig) -> Self {
185        let mut router = Self {
186            handlers: HashMap::new(),
187            streaming_handlers: HashMap::new(),
188            adapters: HashMap::new(),
189            routes: Vec::new(),
190            states: Arc::new(std::sync::RwLock::new(HashMap::new())),
191            handler_metas: HashMap::new(),
192            config: Some(config.clone()),
193        };
194
195        // Auto-register adapters based on config
196        if config.has_protocol("rest") {
197            router.add_adapter(Box::new(RestAdapter::new()));
198        }
199        if config.has_protocol("graphql") {
200            router.add_adapter(Box::new(GraphQLAdapter::new()));
201        }
202        if config.has_protocol("grpc") {
203            router.add_adapter(Box::new(GrpcAdapter::new()));
204        }
205
206        router
207    }
208
209    /// Add shared state for dependency injection (builder pattern).
210    ///
211    /// Can be called multiple times with different types. Each state type
212    /// is stored independently and looked up by `TypeId` at registration time.
213    /// Calling twice with the same `S` replaces the previous value.
214    ///
215    /// ```rust,ignore
216    /// let router = Router::new()
217    ///     .with_state(db_pool)       // handlers can request State<Arc<DbPool>>
218    ///     .with_state(app_handle);   // handlers can request State<Arc<AppHandle>>
219    /// ```
220    pub fn with_state<S: Send + Sync + 'static>(mut self, state: S) -> Self {
221        self.insert_state::<S>(state);
222        self
223    }
224
225    /// Add shared state for dependency injection (mutable, non-builder).
226    ///
227    /// Like `with_state` but takes `&mut self` instead of consuming `self`.
228    /// Useful when the state is not available at router construction time
229    /// (e.g., Tauri's `AppHandle` which is only available during plugin setup).
230    /// Calling twice with the same `S` replaces the previous value.
231    pub fn inject_state<S: Send + Sync + 'static>(&mut self, state: S) {
232        self.insert_state::<S>(state);
233    }
234
235    fn insert_state<S: Send + Sync + 'static>(&mut self, state: S) {
236        let id = std::any::TypeId::of::<S>();
237        let mut map = self.states.write().expect("state lock poisoned");
238        if map.contains_key(&id) {
239            #[cfg(debug_assertions)]
240            eprintln!(
241                "allframe: with_state called twice for type `{}` — previous value replaced",
242                std::any::type_name::<S>()
243            );
244        }
245        map.insert(id, Arc::new(state));
246    }
247
248    /// Returns a handle to the shared state map.
249    ///
250    /// This is the same `Arc` used internally, so state injected through
251    /// the returned handle is visible to handlers at call time. Used by
252    /// `BootContext` to inject state during async boot.
253    pub fn shared_states(&self) -> SharedStateMap {
254        self.states.clone()
255    }
256
257    /// Register a handler with a name (zero-arg, backward compatible)
258    pub fn register<F, Fut>(&mut self, name: &str, handler: F)
259    where
260        F: Fn() -> Fut + Send + Sync + 'static,
261        Fut: Future<Output = String> + Send + 'static,
262    {
263        self.handlers
264            .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
265    }
266
267    /// Register a handler that receives typed, deserialized args
268    pub fn register_with_args<T, F, Fut>(&mut self, name: &str, handler: F)
269    where
270        T: DeserializeOwned + Send + 'static,
271        F: Fn(T) -> Fut + Send + Sync + 'static,
272        Fut: Future<Output = String> + Send + 'static,
273    {
274        self.handlers
275            .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
276    }
277
278    /// Register a handler that receives injected state and typed args
279    ///
280    /// # Panics
281    ///
282    /// Panics at registration time if `with_state::<S>()` was not called.
283    pub fn register_with_state<S, T, F, Fut>(&mut self, name: &str, handler: F)
284    where
285        S: Send + Sync + 'static,
286        T: DeserializeOwned + Send + 'static,
287        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
288        Fut: Future<Output = String> + Send + 'static,
289    {
290        let state = self.states.clone();
291        self.handlers
292            .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
293    }
294
295    /// Register a handler that receives only injected state (no args)
296    ///
297    /// # Panics
298    ///
299    /// Panics at registration time if `with_state::<S>()` was not called.
300    pub fn register_with_state_only<S, F, Fut>(&mut self, name: &str, handler: F)
301    where
302        S: Send + Sync + 'static,
303        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
304        Fut: Future<Output = String> + Send + 'static,
305    {
306        let state = self.states.clone();
307        self.handlers
308            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
309    }
310
311    // ─── Typed return registration (auto-serialize via Json wrapper) ─────
312
313    /// Register a handler that returns `R: Serialize` (auto-serialized to JSON)
314    pub fn register_typed<R, F, Fut>(&mut self, name: &str, handler: F)
315    where
316        R: Serialize + Send + 'static,
317        F: Fn() -> Fut + Send + Sync + 'static,
318        Fut: Future<Output = R> + Send + 'static,
319    {
320        let wrapped = move || {
321            let fut = handler();
322            async move { Json(fut.await) }
323        };
324        self.handlers
325            .insert(name.to_string(), Box::new(HandlerFn::new(wrapped)));
326    }
327
328    /// Register a handler that accepts typed args and returns `R: Serialize`
329    pub fn register_typed_with_args<T, R, F, Fut>(&mut self, name: &str, handler: F)
330    where
331        T: DeserializeOwned + Send + 'static,
332        R: Serialize + Send + 'static,
333        F: Fn(T) -> Fut + Send + Sync + 'static,
334        Fut: Future<Output = R> + Send + 'static,
335    {
336        let wrapped = move |args: T| {
337            let fut = handler(args);
338            async move { Json(fut.await) }
339        };
340        self.handlers
341            .insert(name.to_string(), Box::new(HandlerWithArgs::new(wrapped)));
342    }
343
344    /// Register a handler that receives state + typed args and returns `R: Serialize`
345    pub fn register_typed_with_state<S, T, R, F, Fut>(&mut self, name: &str, handler: F)
346    where
347        S: Send + Sync + 'static,
348        T: DeserializeOwned + Send + 'static,
349        R: Serialize + Send + 'static,
350        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
351        Fut: Future<Output = R> + Send + 'static,
352    {
353        let state = self.states.clone();
354        let wrapped = move |s: State<Arc<S>>, args: T| {
355            let fut = handler(s, args);
356            async move { Json(fut.await) }
357        };
358        self.handlers
359            .insert(name.to_string(), Box::new(HandlerWithState::new(wrapped, state)));
360    }
361
362    /// Register a handler that receives state only and returns `R: Serialize`
363    pub fn register_typed_with_state_only<S, R, F, Fut>(&mut self, name: &str, handler: F)
364    where
365        S: Send + Sync + 'static,
366        R: Serialize + Send + 'static,
367        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
368        Fut: Future<Output = R> + Send + 'static,
369    {
370        let state = self.states.clone();
371        let wrapped = move |s: State<Arc<S>>| {
372            let fut = handler(s);
373            async move { Json(fut.await) }
374        };
375        self.handlers
376            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(wrapped, state)));
377    }
378
379    // ─── Result return registration ─────────────────────────────────────
380
381    /// Register a handler returning `Result<R, E>` (no args)
382    ///
383    /// On `Ok(value)`, `value` is serialized to JSON. On `Err(e)`, the error
384    /// is returned as a string.
385    pub fn register_result<R, E, F, Fut>(&mut self, name: &str, handler: F)
386    where
387        R: Serialize + Send + 'static,
388        E: std::fmt::Display + Send + 'static,
389        F: Fn() -> Fut + Send + Sync + 'static,
390        Fut: Future<Output = Result<R, E>> + Send + 'static,
391    {
392        self.handlers
393            .insert(name.to_string(), Box::new(HandlerFn::new(handler)));
394    }
395
396    /// Register a handler returning `Result<R, E>` with typed args
397    pub fn register_result_with_args<T, R, E, F, Fut>(&mut self, name: &str, handler: F)
398    where
399        T: DeserializeOwned + Send + 'static,
400        R: Serialize + Send + 'static,
401        E: std::fmt::Display + Send + 'static,
402        F: Fn(T) -> Fut + Send + Sync + 'static,
403        Fut: Future<Output = Result<R, E>> + Send + 'static,
404    {
405        self.handlers
406            .insert(name.to_string(), Box::new(HandlerWithArgs::new(handler)));
407    }
408
409    /// Register a handler returning `Result<R, E>` with state + typed args
410    pub fn register_result_with_state<S, T, R, E, F, Fut>(&mut self, name: &str, handler: F)
411    where
412        S: Send + Sync + 'static,
413        T: DeserializeOwned + Send + 'static,
414        R: Serialize + Send + 'static,
415        E: std::fmt::Display + Send + 'static,
416        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
417        Fut: Future<Output = Result<R, E>> + Send + 'static,
418    {
419        let state = self.states.clone();
420        self.handlers
421            .insert(name.to_string(), Box::new(HandlerWithState::new(handler, state)));
422    }
423
424    /// Register a handler returning `Result<R, E>` with state only
425    pub fn register_result_with_state_only<S, R, E, F, Fut>(&mut self, name: &str, handler: F)
426    where
427        S: Send + Sync + 'static,
428        R: Serialize + Send + 'static,
429        E: std::fmt::Display + Send + 'static,
430        F: Fn(State<Arc<S>>) -> Fut + Send + Sync + 'static,
431        Fut: Future<Output = Result<R, E>> + Send + 'static,
432    {
433        let state = self.states.clone();
434        self.handlers
435            .insert(name.to_string(), Box::new(HandlerWithStateOnly::new(handler, state)));
436    }
437
438    /// Get the number of registered handlers (request/response only)
439    pub fn handlers_count(&self) -> usize {
440        self.handlers.len()
441    }
442
443    // ─── Streaming handler registration ─────────────────────────────────
444
445    /// Register a streaming handler (no args, receives StreamSender)
446    pub fn register_streaming<F, Fut, R>(&mut self, name: &str, handler: F)
447    where
448        F: Fn(StreamSender) -> Fut + Send + Sync + 'static,
449        Fut: Future<Output = R> + Send + 'static,
450        R: IntoHandlerResult + 'static,
451    {
452        self.streaming_handlers
453            .insert(name.to_string(), Box::new(StreamingHandlerFn::new(handler)));
454    }
455
456    /// Register a streaming handler with typed args
457    pub fn register_streaming_with_args<T, F, Fut, R>(&mut self, name: &str, handler: F)
458    where
459        T: DeserializeOwned + Send + 'static,
460        F: Fn(T, StreamSender) -> Fut + Send + Sync + 'static,
461        Fut: Future<Output = R> + Send + 'static,
462        R: IntoHandlerResult + 'static,
463    {
464        self.streaming_handlers
465            .insert(name.to_string(), Box::new(StreamingHandlerWithArgs::new(handler)));
466    }
467
468    /// Register a streaming handler with state and typed args
469    pub fn register_streaming_with_state<S, T, F, Fut, R>(&mut self, name: &str, handler: F)
470    where
471        S: Send + Sync + 'static,
472        T: DeserializeOwned + Send + 'static,
473        F: Fn(State<Arc<S>>, T, StreamSender) -> Fut + Send + Sync + 'static,
474        Fut: Future<Output = R> + Send + 'static,
475        R: IntoHandlerResult + 'static,
476    {
477        let state = self.states.clone();
478        self.streaming_handlers
479            .insert(name.to_string(), Box::new(StreamingHandlerWithState::new(handler, state)));
480    }
481
482    /// Register a streaming handler with state only (no args)
483    pub fn register_streaming_with_state_only<S, F, Fut, R>(&mut self, name: &str, handler: F)
484    where
485        S: Send + Sync + 'static,
486        F: Fn(State<Arc<S>>, StreamSender) -> Fut + Send + Sync + 'static,
487        Fut: Future<Output = R> + Send + 'static,
488        R: IntoHandlerResult + 'static,
489    {
490        let state = self.states.clone();
491        self.streaming_handlers
492            .insert(name.to_string(), Box::new(StreamingHandlerWithStateOnly::new(handler, state)));
493    }
494
495    /// Register a handler that returns a `Stream` of items (no args).
496    ///
497    /// The stream is internally bridged to a `StreamSender` channel.
498    /// Items are forwarded through a bounded channel (default capacity 64).
499    /// Register a handler that returns a `Stream` of items (no args).
500    ///
501    /// The stream is internally bridged to a `StreamSender` channel.
502    /// Items are forwarded through a bounded channel (default capacity 64).
503    pub fn register_stream<T, St, F, Fut>(&mut self, name: &str, handler: F)
504    where
505        T: IntoStreamItem + 'static,
506        St: Stream<Item = T> + Send + 'static,
507        F: Fn() -> Fut + Send + Sync + 'static,
508        Fut: Future<Output = St> + Send + 'static,
509    {
510        self.register_streaming(name, move |tx: StreamSender| {
511            let stream_fut = handler();
512            async move {
513                drive_stream(stream_fut.await, &tx).await
514            }
515        });
516    }
517
518    /// Register a handler that takes typed args and returns a `Stream` of items.
519    pub fn register_stream_with_args<T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
520    where
521        T: DeserializeOwned + Send + 'static,
522        Item: IntoStreamItem + 'static,
523        St: Stream<Item = Item> + Send + 'static,
524        F: Fn(T) -> Fut + Send + Sync + 'static,
525        Fut: Future<Output = St> + Send + 'static,
526    {
527        self.register_streaming_with_args::<T, _, _, _>(name, move |args: T, tx: StreamSender| {
528            let stream_fut = handler(args);
529            async move {
530                drive_stream(stream_fut.await, &tx).await
531            }
532        });
533    }
534
535    /// Register a handler that takes state + typed args and returns a `Stream` of items.
536    pub fn register_stream_with_state<S, T, Item, St, F, Fut>(&mut self, name: &str, handler: F)
537    where
538        S: Send + Sync + 'static,
539        T: DeserializeOwned + Send + 'static,
540        Item: IntoStreamItem + 'static,
541        St: Stream<Item = Item> + Send + 'static,
542        F: Fn(State<Arc<S>>, T) -> Fut + Send + Sync + 'static,
543        Fut: Future<Output = St> + Send + 'static,
544    {
545        self.register_streaming_with_state::<S, T, _, _, _>(name, move |state: State<Arc<S>>, args: T, tx: StreamSender| {
546            let stream_fut = handler(state, args);
547            async move {
548                drive_stream(stream_fut.await, &tx).await
549            }
550        });
551    }
552
553    /// Check if a handler is a streaming handler
554    pub fn is_streaming(&self, name: &str) -> bool {
555        self.streaming_handlers.contains_key(name)
556    }
557
558    /// Call a streaming handler by name.
559    ///
560    /// Creates a bounded channel, passes the sender to the handler,
561    /// and returns `(receiver, completion_future)`. The completion future
562    /// resolves with the handler's final result.
563    ///
564    /// Note: the returned future borrows `self`. For use in contexts where
565    /// a `'static` future is needed (e.g., `tokio::spawn`), use
566    /// `spawn_streaming_handler` instead.
567    #[allow(clippy::type_complexity)]
568    pub fn call_streaming_handler(
569        &self,
570        name: &str,
571        args: &str,
572    ) -> Result<
573        (
574            StreamReceiver,
575            Pin<Box<dyn Future<Output = Result<String, String>> + Send + '_>>,
576        ),
577        String,
578    > {
579        let handler = self
580            .streaming_handlers
581            .get(name)
582            .ok_or_else(|| format!("Streaming handler '{}' not found", name))?;
583
584        let (tx, rx) = StreamSender::channel();
585        let fut = handler.call_streaming(args, tx);
586        Ok((rx, fut))
587    }
588
589    /// Spawn a streaming handler as a tokio task.
590    ///
591    /// Like `call_streaming_handler` but returns a `'static` receiver and
592    /// `JoinHandle`, suitable for use with `tokio::spawn`.
593    #[allow(clippy::type_complexity)]
594    pub fn spawn_streaming_handler(
595        self: &Arc<Self>,
596        name: &str,
597        args: &str,
598    ) -> Result<
599        (
600            StreamReceiver,
601            tokio::task::JoinHandle<Result<String, String>>,
602        ),
603        String,
604    > {
605        if !self.streaming_handlers.contains_key(name) {
606            return Err(format!("Streaming handler '{}' not found", name));
607        }
608
609        let router = self.clone();
610        let name = name.to_string();
611        let args = args.to_string();
612
613        let (tx, rx) = StreamSender::channel();
614
615        let handle = tokio::spawn(async move {
616            let handler = router
617                .streaming_handlers
618                .get(&name)
619                .expect("handler verified to exist");
620            handler.call_streaming(&args, tx).await
621        });
622
623        Ok((rx, handle))
624    }
625
626    // ─── TypeScript codegen metadata ────────────────────────────────────
627
628    /// Attach type metadata to a handler for TypeScript client generation
629    ///
630    /// The metadata describes the handler's argument fields and return type,
631    /// which `generate_ts_client()` uses to generate typed async functions.
632    ///
633    /// # Example
634    ///
635    /// ```rust
636    /// use allframe_core::router::{Router, TsField, TsType};
637    ///
638    /// let mut router = Router::new();
639    /// router.register("get_user", || async { r#"{"id":1}"#.to_string() });
640    /// router.describe_handler("get_user", vec![], TsType::Object(vec![
641    ///     TsField::new("id", TsType::Number),
642    ///     TsField::new("name", TsType::String),
643    /// ]));
644    /// ```
645    pub fn describe_handler(
646        &mut self,
647        name: &str,
648        args: Vec<TsField>,
649        returns: TsType,
650    ) {
651        assert!(
652            self.handlers.contains_key(name),
653            "describe_handler: handler '{}' not registered",
654            name
655        );
656        self.handler_metas
657            .insert(name.to_string(), HandlerMeta::new(args, returns));
658    }
659
660    /// Attach type metadata to a streaming handler for TypeScript client generation
661    pub fn describe_streaming_handler(
662        &mut self,
663        name: &str,
664        args: Vec<TsField>,
665        item_type: TsType,
666        final_type: TsType,
667    ) {
668        assert!(
669            self.streaming_handlers.contains_key(name),
670            "describe_streaming_handler: streaming handler '{}' not registered",
671            name
672        );
673        self.handler_metas
674            .insert(name.to_string(), HandlerMeta::streaming(args, item_type, final_type));
675    }
676
677    /// Generate a complete TypeScript client module from all described handlers
678    ///
679    /// Returns a string containing TypeScript code with typed async functions
680    /// for each handler that has metadata attached via `describe_handler()`.
681    ///
682    /// # Example
683    ///
684    /// ```rust
685    /// use allframe_core::router::{Router, TsField, TsType};
686    ///
687    /// let mut router = Router::new();
688    /// router.register("get_user", || async { r#"{"id":1}"#.to_string() });
689    /// router.describe_handler("get_user", vec![
690    ///     TsField::new("id", TsType::Number),
691    /// ], TsType::Object(vec![
692    ///     TsField::new("id", TsType::Number),
693    ///     TsField::new("name", TsType::String),
694    /// ]));
695    ///
696    /// let ts_code = router.generate_ts_client();
697    /// assert!(ts_code.contains("export async function getUser"));
698    /// ```
699    pub fn generate_ts_client(&self) -> String {
700        generate_ts_client(&self.handler_metas)
701    }
702
703    /// Get handler metadata (for inspection/testing)
704    pub fn handler_meta(&self, name: &str) -> Option<&HandlerMeta> {
705        self.handler_metas.get(name)
706    }
707
708    /// Add a protocol adapter
709    pub fn add_adapter(&mut self, adapter: Box<dyn ProtocolAdapter>) {
710        self.adapters.insert(adapter.name().to_string(), adapter);
711    }
712
713    /// Check if an adapter is registered
714    pub fn has_adapter(&self, name: &str) -> bool {
715        self.adapters.contains_key(name)
716    }
717
718    /// Get an adapter by name
719    pub fn get_adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
720        self.adapters.get(name).map(|b| &**b)
721    }
722
723    /// Route a request through the appropriate protocol adapter
724    pub async fn route_request(&self, protocol: &str, request: &str) -> Result<String, String> {
725        let adapter = self
726            .get_adapter(protocol)
727            .ok_or_else(|| format!("Adapter not found: {}", protocol))?;
728
729        adapter.handle(request).await
730    }
731
732    /// Execute a handler by name (zero-arg shorthand)
733    pub async fn execute(&self, name: &str) -> Result<String, String> {
734        self.execute_with_args(name, "{}").await
735    }
736
737    /// Execute a handler by name with JSON args
738    pub async fn execute_with_args(&self, name: &str, args: &str) -> Result<String, String> {
739        match self.handlers.get(name) {
740            Some(handler) => handler.call(args).await,
741            None => Err(format!("Handler '{}' not found", name)),
742        }
743    }
744
745    /// List all registered handler names (both request/response and streaming)
746    ///
747    /// Returns a vector of all handler names that have been registered
748    /// with this router. Used by MCP server for tool discovery.
749    pub fn list_handlers(&self) -> Vec<String> {
750        let mut names: Vec<String> = self.handlers.keys().cloned().collect();
751        names.extend(self.streaming_handlers.keys().cloned());
752        names
753    }
754
755    /// Call a handler by name with request data (JSON args)
756    ///
757    /// Forwards the request string as args to the handler.
758    /// Used by MCP server and Tauri plugin.
759    pub async fn call_handler(&self, name: &str, request: &str) -> Result<String, String> {
760        self.execute_with_args(name, request).await
761    }
762
763    /// Check if handler can be called via REST
764    pub fn can_handle_rest(&self, _name: &str) -> bool {
765        self.has_adapter("rest")
766    }
767
768    /// Check if handler can be called via GraphQL
769    pub fn can_handle_graphql(&self, _name: &str) -> bool {
770        self.has_adapter("graphql")
771    }
772
773    /// Check if handler can be called via gRPC
774    pub fn can_handle_grpc(&self, _name: &str) -> bool {
775        self.has_adapter("grpc")
776    }
777
778    /// Get list of enabled protocols
779    pub fn enabled_protocols(&self) -> Vec<String> {
780        self.adapters.keys().cloned().collect()
781    }
782
783    /// Add a route with metadata
784    ///
785    /// This stores route metadata that can be used to generate
786    /// documentation (OpenAPI, GraphQL schemas, gRPC reflection).
787    pub fn add_route(&mut self, metadata: RouteMetadata) {
788        self.routes.push(metadata);
789    }
790
791    /// Get all registered routes
792    ///
793    /// Returns an immutable reference to all route metadata.
794    /// This is used for documentation generation.
795    pub fn routes(&self) -> &[RouteMetadata] {
796        &self.routes
797    }
798
799    /// Register a GET route
800    ///
801    /// This is a convenience method that registers both a handler and route
802    /// metadata for a GET request. The handler name is automatically
803    /// generated as "GET:{path}".
804    pub fn get<F, Fut>(&mut self, path: &str, handler: F)
805    where
806        F: Fn() -> Fut + Send + Sync + 'static,
807        Fut: Future<Output = String> + Send + 'static,
808    {
809        let handler_name = format!("GET:{}", path);
810        self.register(&handler_name, handler);
811        self.add_route(RouteMetadata::new(path, Method::GET, "rest"));
812    }
813
814    /// Register a POST route
815    ///
816    /// This is a convenience method that registers both a handler and route
817    /// metadata for a POST request. The handler name is automatically
818    /// generated as "POST:{path}".
819    pub fn post<F, Fut>(&mut self, path: &str, handler: F)
820    where
821        F: Fn() -> Fut + Send + Sync + 'static,
822        Fut: Future<Output = String> + Send + 'static,
823    {
824        let handler_name = format!("POST:{}", path);
825        self.register(&handler_name, handler);
826        self.add_route(RouteMetadata::new(path, Method::POST, "rest"));
827    }
828
829    /// Register a PUT route
830    ///
831    /// This is a convenience method that registers both a handler and route
832    /// metadata for a PUT request. The handler name is automatically
833    /// generated as "PUT:{path}".
834    pub fn put<F, Fut>(&mut self, path: &str, handler: F)
835    where
836        F: Fn() -> Fut + Send + Sync + 'static,
837        Fut: Future<Output = String> + Send + 'static,
838    {
839        let handler_name = format!("PUT:{}", path);
840        self.register(&handler_name, handler);
841        self.add_route(RouteMetadata::new(path, Method::PUT, "rest"));
842    }
843
844    /// Register a DELETE route
845    ///
846    /// This is a convenience method that registers both a handler and route
847    /// metadata for a DELETE request. The handler name is automatically
848    /// generated as "DELETE:{path}".
849    pub fn delete<F, Fut>(&mut self, path: &str, handler: F)
850    where
851        F: Fn() -> Fut + Send + Sync + 'static,
852        Fut: Future<Output = String> + Send + 'static,
853    {
854        let handler_name = format!("DELETE:{}", path);
855        self.register(&handler_name, handler);
856        self.add_route(RouteMetadata::new(path, Method::DELETE, "rest"));
857    }
858
859    /// Register a PATCH route
860    ///
861    /// This is a convenience method that registers both a handler and route
862    /// metadata for a PATCH request. The handler name is automatically
863    /// generated as "PATCH:{path}".
864    pub fn patch<F, Fut>(&mut self, path: &str, handler: F)
865    where
866        F: Fn() -> Fut + Send + Sync + 'static,
867        Fut: Future<Output = String> + Send + 'static,
868    {
869        let handler_name = format!("PATCH:{}", path);
870        self.register(&handler_name, handler);
871        self.add_route(RouteMetadata::new(path, Method::PATCH, "rest"));
872    }
873
874    /// Register a HEAD route
875    ///
876    /// This is a convenience method that registers both a handler and route
877    /// metadata for a HEAD request. The handler name is automatically
878    /// generated as "HEAD:{path}".
879    pub fn head<F, Fut>(&mut self, path: &str, handler: F)
880    where
881        F: Fn() -> Fut + Send + Sync + 'static,
882        Fut: Future<Output = String> + Send + 'static,
883    {
884        let handler_name = format!("HEAD:{}", path);
885        self.register(&handler_name, handler);
886        self.add_route(RouteMetadata::new(path, Method::HEAD, "rest"));
887    }
888
889    /// Register an OPTIONS route
890    ///
891    /// This is a convenience method that registers both a handler and route
892    /// metadata for an OPTIONS request. The handler name is automatically
893    /// generated as "OPTIONS:{path}".
894    pub fn options<F, Fut>(&mut self, path: &str, handler: F)
895    where
896        F: Fn() -> Fut + Send + Sync + 'static,
897        Fut: Future<Output = String> + Send + 'static,
898    {
899        let handler_name = format!("OPTIONS:{}", path);
900        self.register(&handler_name, handler);
901        self.add_route(RouteMetadata::new(path, Method::OPTIONS, "rest"));
902    }
903
904    /// Call handler via REST
905    pub async fn call_rest(&self, method: &str, path: &str) -> Result<String, String> {
906        let adapter = self
907            .adapters
908            .get("rest")
909            .ok_or_else(|| "REST adapter not enabled".to_string())?;
910
911        let request = format!("{} {}", method, path);
912        adapter.handle(&request).await
913    }
914
915    /// Call handler via GraphQL
916    pub async fn call_graphql(&self, query: &str) -> Result<String, String> {
917        let adapter = self
918            .adapters
919            .get("graphql")
920            .ok_or_else(|| "GraphQL adapter not enabled".to_string())?;
921
922        adapter.handle(query).await
923    }
924
925    /// Call handler via gRPC
926    pub async fn call_grpc(&self, method: &str, request: &str) -> Result<String, String> {
927        let adapter = self
928            .adapters
929            .get("grpc")
930            .ok_or_else(|| "gRPC adapter not enabled".to_string())?;
931
932        let grpc_request = format!("{}:{}", method, request);
933        adapter.handle(&grpc_request).await
934    }
935
936    /// Generate Scalar documentation HTML with default configuration
937    ///
938    /// This is a convenience method that generates a complete HTML page
939    /// with Scalar UI for interactive API documentation.
940    ///
941    /// # Arguments
942    ///
943    /// * `title` - API title
944    /// * `version` - API version
945    ///
946    /// # Example
947    ///
948    /// ```rust
949    /// use allframe_core::router::Router;
950    ///
951    /// let mut router = Router::new();
952    /// router.get("/users", || async { "Users".to_string() });
953    ///
954    /// let html = router.scalar("My API", "1.0.0");
955    /// // Serve this HTML at /docs endpoint
956    /// ```
957    pub fn scalar(&self, title: &str, version: &str) -> String {
958        let config = scalar::ScalarConfig::default();
959        self.scalar_docs(config, title, version)
960    }
961
962    /// Generate Scalar documentation HTML with custom configuration
963    ///
964    /// This method allows full customization of the Scalar UI appearance
965    /// and behavior.
966    ///
967    /// # Arguments
968    ///
969    /// * `config` - Scalar configuration
970    /// * `title` - API title
971    /// * `version` - API version
972    ///
973    /// # Example
974    ///
975    /// ```rust
976    /// use allframe_core::router::{Router, ScalarConfig, ScalarTheme};
977    ///
978    /// let mut router = Router::new();
979    /// router.get("/users", || async { "Users".to_string() });
980    ///
981    /// let config = ScalarConfig::new()
982    ///     .theme(ScalarTheme::Light)
983    ///     .show_sidebar(false);
984    ///
985    /// let html = router.scalar_docs(config, "My API", "1.0.0");
986    /// ```
987    pub fn scalar_docs(&self, config: scalar::ScalarConfig, title: &str, version: &str) -> String {
988        // Generate OpenAPI spec
989        let spec = OpenApiGenerator::new(title, version).generate(self);
990        let spec_json = serde_json::to_string(&spec).unwrap_or_else(|_| "{}".to_string());
991
992        // Generate Scalar HTML
993        scalar::scalar_html(&config, title, &spec_json)
994    }
995}
996
997impl Default for Router {
998    fn default() -> Self {
999        Self::new()
1000    }
1001}
1002
1003/// Bulk-register handler functions with a Router.
1004///
1005/// Each function is referenced by path in the expansion, so the compiler
1006/// sees it as used — eliminating false `dead_code` warnings that occur when
1007/// handler functions are only referenced through closure-based registration.
1008///
1009/// # Syntax
1010///
1011/// ```rust,ignore
1012/// use allframe_core::register_handlers;
1013///
1014/// register_handlers!(router, [
1015///     // Basic handler (zero-arg, returns String)
1016///     "health" => health_check,
1017///
1018///     // Handler with typed, deserializable args
1019///     args "greet" => greet,
1020///
1021///     // Streaming handler (receives StreamSender)
1022///     streaming "feed" => live_feed,
1023///
1024///     // Streaming handler with typed args
1025///     streaming args "search" => search_stream,
1026///
1027///     // State-only handler (receives State<Arc<S>>)
1028///     state "get_status" => get_ollama_status,
1029///
1030///     // State with typed args
1031///     state args "save_key" => save_api_key,
1032///
1033///     // State streaming (receives State<Arc<S>> + StreamSender)
1034///     state streaming "stream_chat" => stream_chat,
1035///
1036///     // State streaming with typed args
1037///     state streaming args "start_job" => start_orchestrator,
1038/// ]);
1039/// ```
1040///
1041/// # Expands to
1042///
1043/// ```rust,ignore
1044/// router.register("health", health_check);
1045/// router.register_with_args("greet", greet);
1046/// router.register_streaming("feed", live_feed);
1047/// router.register_streaming_with_args("search", search_stream);
1048/// router.register_with_state_only("get_status", get_ollama_status);
1049/// router.register_with_state("save_key", save_api_key);
1050/// router.register_streaming_with_state_only("stream_chat", stream_chat);
1051/// router.register_streaming_with_state("start_job", start_orchestrator);
1052/// ```
1053///
1054/// # Why this helps
1055///
1056/// When handler functions are defined in separate modules and only called via
1057/// `router.register("name", || async { handler().await })`, the compiler
1058/// cannot always trace the usage chain and reports `dead_code` warnings.
1059/// This macro passes each function directly as a function item, making the
1060/// reference visible to `rustc`'s dead-code analysis.
1061#[macro_export]
1062macro_rules! register_handlers {
1063    ($router:expr, [ $($entry:tt)* ]) => {
1064        $crate::register_handlers!(@entries $router, $($entry)*)
1065    };
1066
1067    // Terminal case
1068    (@entries $router:expr, ) => {};
1069
1070    // Basic: "name" => handler,
1071    (@entries $router:expr, $name:literal => $handler:path, $($rest:tt)*) => {
1072        $router.register($name, $handler);
1073        $crate::register_handlers!(@entries $router, $($rest)*)
1074    };
1075
1076    // With args: args "name" => handler,
1077    (@entries $router:expr, args $name:literal => $handler:path, $($rest:tt)*) => {
1078        $router.register_with_args($name, $handler);
1079        $crate::register_handlers!(@entries $router, $($rest)*)
1080    };
1081
1082    // Streaming: streaming "name" => handler,
1083    (@entries $router:expr, streaming $name:literal => $handler:path, $($rest:tt)*) => {
1084        $router.register_streaming($name, $handler);
1085        $crate::register_handlers!(@entries $router, $($rest)*)
1086    };
1087
1088    // Streaming with args: streaming args "name" => handler,
1089    (@entries $router:expr, streaming args $name:literal => $handler:path, $($rest:tt)*) => {
1090        $router.register_streaming_with_args($name, $handler);
1091        $crate::register_handlers!(@entries $router, $($rest)*)
1092    };
1093
1094    // State only: state "name" => handler,
1095    (@entries $router:expr, state $name:literal => $handler:path, $($rest:tt)*) => {
1096        $router.register_with_state_only($name, $handler);
1097        $crate::register_handlers!(@entries $router, $($rest)*)
1098    };
1099
1100    // State with args: state args "name" => handler,
1101    (@entries $router:expr, state args $name:literal => $handler:path, $($rest:tt)*) => {
1102        $router.register_with_state($name, $handler);
1103        $crate::register_handlers!(@entries $router, $($rest)*)
1104    };
1105
1106    // State streaming: state streaming "name" => handler,
1107    (@entries $router:expr, state streaming $name:literal => $handler:path, $($rest:tt)*) => {
1108        $router.register_streaming_with_state_only($name, $handler);
1109        $crate::register_handlers!(@entries $router, $($rest)*)
1110    };
1111
1112    // State streaming with args: state streaming args "name" => handler,
1113    (@entries $router:expr, state streaming args $name:literal => $handler:path, $($rest:tt)*) => {
1114        $router.register_streaming_with_state($name, $handler);
1115        $crate::register_handlers!(@entries $router, $($rest)*)
1116    };
1117}
1118
1119#[cfg(test)]
1120mod tests {
1121    use super::*;
1122
1123    #[tokio::test]
1124    async fn test_router_creation() {
1125        let router = Router::new();
1126        assert_eq!(router.handlers_count(), 0);
1127    }
1128
1129    #[tokio::test]
1130    async fn test_handler_registration() {
1131        let mut router = Router::new();
1132        router.register("test", || async { "Hello".to_string() });
1133        assert_eq!(router.handlers_count(), 1);
1134    }
1135
1136    #[tokio::test]
1137    async fn test_handler_execution() {
1138        let mut router = Router::new();
1139        router.register("test", || async { "Hello".to_string() });
1140        let result = router.execute("test").await;
1141        assert_eq!(result, Ok("Hello".to_string()));
1142    }
1143
1144    // New tests for route metadata tracking
1145    #[tokio::test]
1146    async fn test_router_starts_with_no_routes() {
1147        let router = Router::new();
1148        let routes = router.routes();
1149        assert_eq!(routes.len(), 0);
1150    }
1151
1152    #[tokio::test]
1153    async fn test_add_route_metadata() {
1154        let mut router = Router::new();
1155        let metadata = RouteMetadata::new("/users", "GET", "rest");
1156
1157        router.add_route(metadata.clone());
1158
1159        let routes = router.routes();
1160        assert_eq!(routes.len(), 1);
1161        assert_eq!(routes[0].path, "/users");
1162        assert_eq!(routes[0].method, "GET");
1163        assert_eq!(routes[0].protocol, "rest");
1164    }
1165
1166    #[tokio::test]
1167    async fn test_add_multiple_routes() {
1168        let mut router = Router::new();
1169
1170        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1171        router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1172        router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1173
1174        let routes = router.routes();
1175        assert_eq!(routes.len(), 3);
1176    }
1177
1178    #[tokio::test]
1179    async fn test_routes_with_different_protocols() {
1180        let mut router = Router::new();
1181
1182        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1183        router.add_route(RouteMetadata::new("users", "query", "graphql"));
1184        router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1185
1186        let routes = router.routes();
1187        assert_eq!(routes.len(), 3);
1188
1189        assert_eq!(routes[0].protocol, "rest");
1190        assert_eq!(routes[1].protocol, "graphql");
1191        assert_eq!(routes[2].protocol, "grpc");
1192    }
1193
1194    #[tokio::test]
1195    async fn test_routes_returns_immutable_reference() {
1196        let mut router = Router::new();
1197        router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1198
1199        let routes1 = router.routes();
1200        let routes2 = router.routes();
1201
1202        // Both should have the same data
1203        assert_eq!(routes1.len(), routes2.len());
1204        assert_eq!(routes1[0].path, routes2[0].path);
1205    }
1206
1207    // Tests for type-safe route registration
1208    #[tokio::test]
1209    async fn test_route_get_method() {
1210        let mut router = Router::new();
1211        router.get("/users", || async { "User list".to_string() });
1212
1213        let routes = router.routes();
1214        assert_eq!(routes.len(), 1);
1215        assert_eq!(routes[0].path, "/users");
1216        assert_eq!(routes[0].method, "GET");
1217        assert_eq!(routes[0].protocol, "rest");
1218    }
1219
1220    #[tokio::test]
1221    async fn test_route_post_method() {
1222        let mut router = Router::new();
1223        router.post("/users", || async { "User created".to_string() });
1224
1225        let routes = router.routes();
1226        assert_eq!(routes.len(), 1);
1227        assert_eq!(routes[0].path, "/users");
1228        assert_eq!(routes[0].method, "POST");
1229        assert_eq!(routes[0].protocol, "rest");
1230    }
1231
1232    #[tokio::test]
1233    async fn test_route_put_method() {
1234        let mut router = Router::new();
1235        router.put("/users/1", || async { "User updated".to_string() });
1236
1237        let routes = router.routes();
1238        assert_eq!(routes.len(), 1);
1239        assert_eq!(routes[0].method, "PUT");
1240    }
1241
1242    #[tokio::test]
1243    async fn test_route_delete_method() {
1244        let mut router = Router::new();
1245        router.delete("/users/1", || async { "User deleted".to_string() });
1246
1247        let routes = router.routes();
1248        assert_eq!(routes.len(), 1);
1249        assert_eq!(routes[0].method, "DELETE");
1250    }
1251
1252    #[tokio::test]
1253    async fn test_route_patch_method() {
1254        let mut router = Router::new();
1255        router.patch("/users/1", || async { "User patched".to_string() });
1256
1257        let routes = router.routes();
1258        assert_eq!(routes.len(), 1);
1259        assert_eq!(routes[0].method, "PATCH");
1260    }
1261
1262    #[tokio::test]
1263    async fn test_multiple_routes_different_methods() {
1264        let mut router = Router::new();
1265        router.get("/users", || async { "List".to_string() });
1266        router.post("/users", || async { "Create".to_string() });
1267        router.put("/users/1", || async { "Update".to_string() });
1268        router.delete("/users/1", || async { "Delete".to_string() });
1269
1270        let routes = router.routes();
1271        assert_eq!(routes.len(), 4);
1272
1273        assert_eq!(routes[0].method, "GET");
1274        assert_eq!(routes[1].method, "POST");
1275        assert_eq!(routes[2].method, "PUT");
1276        assert_eq!(routes[3].method, "DELETE");
1277    }
1278
1279    #[tokio::test]
1280    async fn test_route_method_with_path_params() {
1281        let mut router = Router::new();
1282        router.get("/users/{id}", || async { "User details".to_string() });
1283        router.get("/users/{id}/posts/{post_id}", || async {
1284            "Post details".to_string()
1285        });
1286
1287        let routes = router.routes();
1288        assert_eq!(routes.len(), 2);
1289        assert_eq!(routes[0].path, "/users/{id}");
1290        assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1291    }
1292
1293    #[tokio::test]
1294    async fn test_route_registration_and_execution() {
1295        let mut router = Router::new();
1296        router.get("/test", || async { "GET response".to_string() });
1297        router.post("/test", || async { "POST response".to_string() });
1298
1299        // Both route metadata and handler should be registered
1300        assert_eq!(router.routes().len(), 2);
1301        assert_eq!(router.handlers_count(), 2);
1302
1303        // Handlers should be executable
1304        let result1 = router.execute("GET:/test").await;
1305        let result2 = router.execute("POST:/test").await;
1306
1307        assert_eq!(result1, Ok("GET response".to_string()));
1308        assert_eq!(result2, Ok("POST response".to_string()));
1309    }
1310
1311    // Tests for Scalar integration
1312    #[tokio::test]
1313    async fn test_scalar_generates_html() {
1314        let mut router = Router::new();
1315        router.get("/users", || async { "Users".to_string() });
1316
1317        let html = router.scalar("Test API", "1.0.0");
1318
1319        assert!(html.contains("<!DOCTYPE html>"));
1320        assert!(html.contains("<title>Test API - API Documentation</title>"));
1321        assert!(html.contains("@scalar/api-reference"));
1322    }
1323
1324    #[tokio::test]
1325    async fn test_scalar_contains_openapi_spec() {
1326        let mut router = Router::new();
1327        router.get("/users", || async { "Users".to_string() });
1328        router.post("/users", || async { "User created".to_string() });
1329
1330        let html = router.scalar("Test API", "1.0.0");
1331
1332        // Should contain the OpenAPI spec
1333        assert!(html.contains("openapi"));
1334        assert!(html.contains("Test API"));
1335        assert!(html.contains("1.0.0"));
1336    }
1337
1338    #[tokio::test]
1339    async fn test_scalar_docs_with_custom_config() {
1340        let mut router = Router::new();
1341        router.get("/users", || async { "Users".to_string() });
1342
1343        let config = scalar::ScalarConfig::new()
1344            .theme(scalar::ScalarTheme::Light)
1345            .show_sidebar(false);
1346
1347        let html = router.scalar_docs(config, "Custom API", "2.0.0");
1348
1349        assert!(html.contains("Custom API"));
1350        assert!(html.contains(r#""theme":"light""#));
1351        assert!(html.contains(r#""showSidebar":false"#));
1352    }
1353
1354    #[tokio::test]
1355    async fn test_scalar_docs_with_custom_css() {
1356        let mut router = Router::new();
1357        router.get("/test", || async { "Test".to_string() });
1358
1359        let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1360
1361        let html = router.scalar_docs(config, "API", "1.0");
1362
1363        assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1364    }
1365
1366    #[tokio::test]
1367    async fn test_scalar_with_multiple_routes() {
1368        let mut router = Router::new();
1369        router.get("/users", || async { "Users".to_string() });
1370        router.post("/users", || async { "Create".to_string() });
1371        router.get("/users/{id}", || async { "User details".to_string() });
1372        router.delete("/users/{id}", || async { "Delete".to_string() });
1373
1374        let html = router.scalar("API", "1.0.0");
1375
1376        // Should contain all routes in the OpenAPI spec
1377        assert!(html.contains("/users"));
1378    }
1379
1380    // Tests for protocol adapter management
1381    #[tokio::test]
1382    async fn test_get_adapter_returns_adapter() {
1383        let mut router = Router::new();
1384        router.add_adapter(Box::new(RestAdapter::new()));
1385
1386        let adapter = router.get_adapter("rest");
1387        assert!(adapter.is_some());
1388        assert_eq!(adapter.unwrap().name(), "rest");
1389    }
1390
1391    #[tokio::test]
1392    async fn test_get_adapter_returns_none_for_missing() {
1393        let router = Router::new();
1394        let adapter = router.get_adapter("rest");
1395        assert!(adapter.is_none());
1396    }
1397
1398    #[tokio::test]
1399    async fn test_route_request_success() {
1400        let mut router = Router::new();
1401        router.register("test_handler", || async { "Success!".to_string() });
1402
1403        // Register adapter with a route
1404        let mut rest_adapter = RestAdapter::new();
1405        rest_adapter.route("GET", "/test", "test_handler");
1406        router.add_adapter(Box::new(rest_adapter));
1407
1408        let result = router.route_request("rest", "GET /test").await;
1409        assert!(result.is_ok());
1410        let response = result.unwrap();
1411        assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1412    }
1413
1414    #[tokio::test]
1415    async fn test_route_request_unknown_adapter() {
1416        let router = Router::new();
1417        let result = router.route_request("unknown", "test").await;
1418        assert!(result.is_err());
1419        assert!(result.unwrap_err().contains("Adapter not found"));
1420    }
1421
1422    #[tokio::test]
1423    async fn test_enabled_protocols_empty() {
1424        let router = Router::new();
1425        let protocols = router.enabled_protocols();
1426        assert_eq!(protocols.len(), 0);
1427    }
1428
1429    #[tokio::test]
1430    async fn test_enabled_protocols_multiple() {
1431        let mut router = Router::new();
1432        router.add_adapter(Box::new(RestAdapter::new()));
1433        router.add_adapter(Box::new(GraphQLAdapter::new()));
1434        router.add_adapter(Box::new(GrpcAdapter::new()));
1435
1436        let protocols = router.enabled_protocols();
1437        assert_eq!(protocols.len(), 3);
1438        assert!(protocols.contains(&"rest".to_string()));
1439        assert!(protocols.contains(&"graphql".to_string()));
1440        assert!(protocols.contains(&"grpc".to_string()));
1441    }
1442
1443    #[tokio::test]
1444    async fn test_can_handle_rest() {
1445        let mut router = Router::new();
1446        assert!(!router.can_handle_rest("test"));
1447
1448        router.add_adapter(Box::new(RestAdapter::new()));
1449        assert!(router.can_handle_rest("test"));
1450    }
1451
1452    #[tokio::test]
1453    async fn test_can_handle_graphql() {
1454        let mut router = Router::new();
1455        assert!(!router.can_handle_graphql("test"));
1456
1457        router.add_adapter(Box::new(GraphQLAdapter::new()));
1458        assert!(router.can_handle_graphql("test"));
1459    }
1460
1461    #[tokio::test]
1462    async fn test_can_handle_grpc() {
1463        let mut router = Router::new();
1464        assert!(!router.can_handle_grpc("test"));
1465
1466        router.add_adapter(Box::new(GrpcAdapter::new()));
1467        assert!(router.can_handle_grpc("test"));
1468    }
1469
1470    // ===== Integration Tests: Multi-Protocol Routing =====
1471
1472    #[tokio::test]
1473    async fn test_integration_single_handler_rest() {
1474        // Test: Single handler exposed via REST
1475        let mut router = Router::new();
1476        router.register("get_user", || async { "User data".to_string() });
1477
1478        // Configure REST adapter
1479        let mut rest = RestAdapter::new();
1480        rest.route("GET", "/users/:id", "get_user");
1481        router.add_adapter(Box::new(rest));
1482
1483        // Route REST request
1484        let response = router.route_request("rest", "GET /users/42").await;
1485        assert!(response.is_ok());
1486        assert!(response.unwrap().contains("get_user"));
1487    }
1488
1489    #[tokio::test]
1490    async fn test_integration_single_handler_graphql() {
1491        // Test: Single handler exposed via GraphQL
1492        let mut router = Router::new();
1493        router.register("get_user", || async { "User data".to_string() });
1494
1495        // Configure GraphQL adapter
1496        let mut graphql = GraphQLAdapter::new();
1497        graphql.query("user", "get_user");
1498        router.add_adapter(Box::new(graphql));
1499
1500        // Route GraphQL request
1501        let response = router.route_request("graphql", "query { user }").await;
1502        assert!(response.is_ok());
1503        assert!(response.unwrap().contains("get_user"));
1504    }
1505
1506    #[tokio::test]
1507    async fn test_integration_single_handler_grpc() {
1508        // Test: Single handler exposed via gRPC
1509        let mut router = Router::new();
1510        router.register("get_user", || async { "User data".to_string() });
1511
1512        // Configure gRPC adapter
1513        let mut grpc = GrpcAdapter::new();
1514        grpc.unary("UserService", "GetUser", "get_user");
1515        router.add_adapter(Box::new(grpc));
1516
1517        // Route gRPC request
1518        let response = router
1519            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1520            .await;
1521        assert!(response.is_ok());
1522        assert!(response.unwrap().contains("get_user"));
1523    }
1524
1525    #[tokio::test]
1526    async fn test_integration_single_handler_all_protocols() {
1527        // Test: Single handler exposed via ALL protocols
1528        let mut router = Router::new();
1529        router.register("get_user", || async { "User data".to_string() });
1530
1531        // Configure REST adapter
1532        let mut rest = RestAdapter::new();
1533        rest.route("GET", "/users/:id", "get_user");
1534        router.add_adapter(Box::new(rest));
1535
1536        // Configure GraphQL adapter
1537        let mut graphql = GraphQLAdapter::new();
1538        graphql.query("user", "get_user");
1539        router.add_adapter(Box::new(graphql));
1540
1541        // Configure gRPC adapter
1542        let mut grpc = GrpcAdapter::new();
1543        grpc.unary("UserService", "GetUser", "get_user");
1544        router.add_adapter(Box::new(grpc));
1545
1546        // Test REST
1547        let rest_response = router.route_request("rest", "GET /users/42").await;
1548        assert!(rest_response.is_ok());
1549        assert!(rest_response.unwrap().contains("get_user"));
1550
1551        // Test GraphQL
1552        let graphql_response = router.route_request("graphql", "query { user }").await;
1553        assert!(graphql_response.is_ok());
1554        assert!(graphql_response.unwrap().contains("get_user"));
1555
1556        // Test gRPC
1557        let grpc_response = router
1558            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1559            .await;
1560        assert!(grpc_response.is_ok());
1561        assert!(grpc_response.unwrap().contains("get_user"));
1562    }
1563
1564    #[tokio::test]
1565    async fn test_integration_multiple_handlers_all_protocols() {
1566        // Test: Multiple handlers, each exposed via all protocols
1567        let mut router = Router::new();
1568        router.register("get_user", || async { "User data".to_string() });
1569        router.register("list_users", || async { "Users list".to_string() });
1570        router.register("create_user", || async { "Created user".to_string() });
1571
1572        // Configure REST adapter
1573        let mut rest = RestAdapter::new();
1574        rest.route("GET", "/users/:id", "get_user");
1575        rest.route("GET", "/users", "list_users");
1576        rest.route("POST", "/users", "create_user");
1577        router.add_adapter(Box::new(rest));
1578
1579        // Configure GraphQL adapter
1580        let mut graphql = GraphQLAdapter::new();
1581        graphql.query("user", "get_user");
1582        graphql.query("users", "list_users");
1583        graphql.mutation("createUser", "create_user");
1584        router.add_adapter(Box::new(graphql));
1585
1586        // Configure gRPC adapter
1587        let mut grpc = GrpcAdapter::new();
1588        grpc.unary("UserService", "GetUser", "get_user");
1589        grpc.unary("UserService", "ListUsers", "list_users");
1590        grpc.unary("UserService", "CreateUser", "create_user");
1591        router.add_adapter(Box::new(grpc));
1592
1593        // Test each handler via each protocol
1594        assert!(router
1595            .route_request("rest", "GET /users/42")
1596            .await
1597            .unwrap()
1598            .contains("get_user"));
1599        assert!(router
1600            .route_request("graphql", "query { user }")
1601            .await
1602            .unwrap()
1603            .contains("get_user"));
1604        assert!(router
1605            .route_request("grpc", "UserService.GetUser:{}")
1606            .await
1607            .unwrap()
1608            .contains("get_user"));
1609    }
1610
1611    #[tokio::test]
1612    async fn test_integration_error_handling_rest_404() {
1613        // Test: REST 404 error
1614        let mut router = Router::new();
1615
1616        let mut rest = RestAdapter::new();
1617        rest.route("GET", "/users/:id", "get_user");
1618        router.add_adapter(Box::new(rest));
1619
1620        let response = router.route_request("rest", "GET /posts/42").await;
1621        assert!(response.is_ok());
1622        assert!(response.unwrap().contains("HTTP 404"));
1623    }
1624
1625    #[tokio::test]
1626    async fn test_integration_error_handling_graphql_not_found() {
1627        // Test: GraphQL operation not found
1628        let mut router = Router::new();
1629
1630        let mut graphql = GraphQLAdapter::new();
1631        graphql.query("user", "get_user");
1632        router.add_adapter(Box::new(graphql));
1633
1634        let response = router.route_request("graphql", "query { post }").await;
1635        assert!(response.is_ok());
1636        assert!(response.unwrap().contains("errors"));
1637    }
1638
1639    #[tokio::test]
1640    async fn test_integration_error_handling_grpc_unimplemented() {
1641        // Test: gRPC method not implemented
1642        let mut router = Router::new();
1643
1644        let mut grpc = GrpcAdapter::new();
1645        grpc.unary("UserService", "GetUser", "get_user");
1646        router.add_adapter(Box::new(grpc));
1647
1648        let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1649        assert!(response.is_ok());
1650        assert!(response.unwrap().contains("grpc-status: 12")); // UNIMPLEMENTED
1651    }
1652
1653    #[tokio::test]
1654    async fn test_integration_unknown_protocol() {
1655        // Test: Unknown protocol error
1656        let router = Router::new();
1657
1658        let response = router.route_request("unknown", "request").await;
1659        assert!(response.is_err());
1660        assert!(response.unwrap_err().contains("Adapter not found"));
1661    }
1662
1663    #[tokio::test]
1664    async fn test_integration_protocol_specific_features_rest_methods() {
1665        // Test: REST-specific HTTP methods
1666        let mut router = Router::new();
1667        router.register("get_users", || async { "Users".to_string() });
1668        router.register("create_user", || async { "Created".to_string() });
1669        router.register("update_user", || async { "Updated".to_string() });
1670        router.register("delete_user", || async { "Deleted".to_string() });
1671
1672        let mut rest = RestAdapter::new();
1673        rest.route("GET", "/users", "get_users");
1674        rest.route("POST", "/users", "create_user");
1675        rest.route("PUT", "/users/:id", "update_user");
1676        rest.route("DELETE", "/users/:id", "delete_user");
1677        router.add_adapter(Box::new(rest));
1678
1679        // Test different HTTP methods
1680        assert!(router
1681            .route_request("rest", "GET /users")
1682            .await
1683            .unwrap()
1684            .contains("get_users"));
1685        assert!(router
1686            .route_request("rest", "POST /users")
1687            .await
1688            .unwrap()
1689            .contains("create_user"));
1690        assert!(router
1691            .route_request("rest", "PUT /users/42")
1692            .await
1693            .unwrap()
1694            .contains("update_user"));
1695        assert!(router
1696            .route_request("rest", "DELETE /users/42")
1697            .await
1698            .unwrap()
1699            .contains("delete_user"));
1700    }
1701
1702    #[tokio::test]
1703    async fn test_integration_protocol_specific_features_graphql_types() {
1704        // Test: GraphQL-specific query vs mutation
1705        let mut router = Router::new();
1706        router.register("get_user", || async { "User".to_string() });
1707        router.register("create_user", || async { "Created".to_string() });
1708
1709        let mut graphql = GraphQLAdapter::new();
1710        graphql.query("user", "get_user");
1711        graphql.mutation("createUser", "create_user");
1712        router.add_adapter(Box::new(graphql));
1713
1714        // Test query
1715        assert!(router
1716            .route_request("graphql", "query { user }")
1717            .await
1718            .unwrap()
1719            .contains("get_user"));
1720
1721        // Test mutation
1722        assert!(router
1723            .route_request("graphql", "mutation { createUser }")
1724            .await
1725            .unwrap()
1726            .contains("create_user"));
1727    }
1728
1729    #[tokio::test]
1730    async fn test_integration_protocol_specific_features_grpc_streaming() {
1731        // Test: gRPC-specific streaming modes
1732        let mut router = Router::new();
1733        router.register("get_user", || async { "User".to_string() });
1734        router.register("list_users", || async { "Users".to_string() });
1735
1736        let mut grpc = GrpcAdapter::new();
1737        grpc.unary("UserService", "GetUser", "get_user");
1738        grpc.server_streaming("UserService", "ListUsers", "list_users");
1739        router.add_adapter(Box::new(grpc));
1740
1741        // Test unary
1742        let unary_response = router
1743            .route_request("grpc", "UserService.GetUser:{}")
1744            .await
1745            .unwrap();
1746        assert!(unary_response.contains("unary"));
1747
1748        // Test server streaming
1749        let streaming_response = router
1750            .route_request("grpc", "UserService.ListUsers:{}")
1751            .await
1752            .unwrap();
1753        assert!(streaming_response.contains("server_streaming"));
1754    }
1755
1756    // ===== Streaming handler registration tests =====
1757
1758    #[tokio::test]
1759    async fn test_register_streaming_handler() {
1760        let mut router = Router::new();
1761        router.register_streaming("stream_data", |tx: StreamSender| async move {
1762            tx.send("item".to_string()).await.ok();
1763            "done".to_string()
1764        });
1765        assert!(router.is_streaming("stream_data"));
1766        assert!(!router.is_streaming("nonexistent"));
1767    }
1768
1769    #[tokio::test]
1770    async fn test_register_streaming_with_args() {
1771        #[derive(serde::Deserialize)]
1772        struct Input {
1773            count: usize,
1774        }
1775
1776        let mut router = Router::new();
1777        router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1778            for i in 0..args.count {
1779                tx.send(format!("item-{i}")).await.ok();
1780            }
1781            "done".to_string()
1782        });
1783        assert!(router.is_streaming("stream_items"));
1784    }
1785
1786    #[tokio::test]
1787    async fn test_streaming_handler_not_in_regular_handlers() {
1788        let mut router = Router::new();
1789        router.register_streaming("stream", |_tx: StreamSender| async move {
1790            "done".to_string()
1791        });
1792        // Streaming handlers are NOT in the regular handlers map
1793        assert_eq!(router.handlers_count(), 0);
1794    }
1795
1796    #[tokio::test]
1797    async fn test_list_handlers_includes_streaming() {
1798        let mut router = Router::new();
1799        router.register("regular", || async { "ok".to_string() });
1800        router.register_streaming("stream", |_tx: StreamSender| async move {
1801            "ok".to_string()
1802        });
1803
1804        let handlers = router.list_handlers();
1805        assert_eq!(handlers.len(), 2);
1806        assert!(handlers.contains(&"regular".to_string()));
1807        assert!(handlers.contains(&"stream".to_string()));
1808    }
1809
1810    #[tokio::test]
1811    async fn test_call_streaming_handler() {
1812        let mut router = Router::new();
1813        router.register_streaming("stream", |tx: StreamSender| async move {
1814            tx.send("a".to_string()).await.ok();
1815            tx.send("b".to_string()).await.ok();
1816            "final".to_string()
1817        });
1818
1819        let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1820        let result = fut.await;
1821
1822        assert_eq!(result, Ok("final".to_string()));
1823        assert_eq!(rx.recv().await, Some("a".to_string()));
1824        assert_eq!(rx.recv().await, Some("b".to_string()));
1825    }
1826
1827    #[tokio::test]
1828    async fn test_call_streaming_handler_with_args() {
1829        #[derive(serde::Deserialize)]
1830        struct Input {
1831            n: usize,
1832        }
1833
1834        let mut router = Router::new();
1835        router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1836            for i in 0..args.n {
1837                tx.send(format!("{i}")).await.ok();
1838            }
1839            format!("counted to {}", args.n)
1840        });
1841
1842        let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1843        let result = fut.await;
1844
1845        assert_eq!(result, Ok("counted to 3".to_string()));
1846        assert_eq!(rx.recv().await, Some("0".to_string()));
1847        assert_eq!(rx.recv().await, Some("1".to_string()));
1848        assert_eq!(rx.recv().await, Some("2".to_string()));
1849    }
1850
1851    #[tokio::test]
1852    async fn test_call_streaming_handler_not_found() {
1853        let router = Router::new();
1854        let result = router.call_streaming_handler("missing", "{}");
1855        assert!(result.is_err());
1856        match result {
1857            Err(e) => assert!(e.contains("not found")),
1858            Ok(_) => panic!("expected error"),
1859        }
1860    }
1861
1862    #[tokio::test]
1863    async fn test_is_streaming_false_for_regular() {
1864        let mut router = Router::new();
1865        router.register("regular", || async { "ok".to_string() });
1866        assert!(!router.is_streaming("regular"));
1867    }
1868
1869    #[tokio::test]
1870    async fn test_mixed_router() {
1871        let mut router = Router::new();
1872        router.register("get_user", || async { "user".to_string() });
1873        router.register_streaming("stream_updates", |tx: StreamSender| async move {
1874            tx.send("update".to_string()).await.ok();
1875            "done".to_string()
1876        });
1877
1878        // Regular handler works
1879        let result = router.execute("get_user").await;
1880        assert_eq!(result, Ok("user".to_string()));
1881
1882        // Streaming handler works
1883        let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1884        let result = fut.await;
1885        assert_eq!(result, Ok("done".to_string()));
1886        assert_eq!(rx.recv().await, Some("update".to_string()));
1887
1888        // Regular handler not found in streaming
1889        assert!(!router.is_streaming("get_user"));
1890        assert!(router.call_streaming_handler("get_user", "{}").is_err());
1891    }
1892
1893    #[tokio::test]
1894    async fn test_register_streaming_with_state() {
1895        struct AppState {
1896            prefix: String,
1897        }
1898
1899        #[derive(serde::Deserialize)]
1900        struct Input {
1901            name: String,
1902        }
1903
1904        let mut router = Router::new().with_state(AppState {
1905            prefix: "Hello".to_string(),
1906        });
1907        router.register_streaming_with_state::<AppState, Input, _, _, _>(
1908            "greet_stream",
1909            |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1910                tx.send(format!("{} {}", state.prefix, args.name))
1911                    .await
1912                    .ok();
1913                "done".to_string()
1914            },
1915        );
1916
1917        let (mut rx, fut) = router
1918            .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1919            .unwrap();
1920        let result = fut.await;
1921
1922        assert_eq!(result, Ok("done".to_string()));
1923        assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1924    }
1925
1926    #[tokio::test]
1927    async fn test_register_streaming_with_state_only() {
1928        struct AppState {
1929            items: Vec<String>,
1930        }
1931
1932        let mut router = Router::new().with_state(AppState {
1933            items: vec!["x".to_string(), "y".to_string()],
1934        });
1935        router.register_streaming_with_state_only::<AppState, _, _, _>(
1936            "list_stream",
1937            |state: State<Arc<AppState>>, tx: StreamSender| async move {
1938                for item in &state.items {
1939                    tx.send(item.clone()).await.ok();
1940                }
1941                format!("listed {}", state.items.len())
1942            },
1943        );
1944
1945        let (mut rx, fut) = router
1946            .call_streaming_handler("list_stream", "{}")
1947            .unwrap();
1948        let result = fut.await;
1949
1950        assert_eq!(result, Ok("listed 2".to_string()));
1951        assert_eq!(rx.recv().await, Some("x".to_string()));
1952        assert_eq!(rx.recv().await, Some("y".to_string()));
1953    }
1954
1955    // ===== Stream return adapter tests =====
1956
1957    #[tokio::test]
1958    async fn test_register_stream_no_args() {
1959        let mut router = Router::new();
1960        router.register_stream("items", || async {
1961            tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1962        });
1963
1964        assert!(router.is_streaming("items"));
1965
1966        let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1967        let _result = fut.await;
1968
1969        assert_eq!(rx.recv().await, Some("a".to_string()));
1970        assert_eq!(rx.recv().await, Some("b".to_string()));
1971        assert_eq!(rx.recv().await, Some("c".to_string()));
1972    }
1973
1974    #[tokio::test]
1975    async fn test_register_stream_with_args() {
1976        #[derive(serde::Deserialize)]
1977        struct Input {
1978            count: usize,
1979        }
1980
1981        let mut router = Router::new();
1982        router.register_stream_with_args("counting", |args: Input| async move {
1983            tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1984        });
1985
1986        assert!(router.is_streaming("counting"));
1987
1988        let (mut rx, fut) = router
1989            .call_streaming_handler("counting", r#"{"count":3}"#)
1990            .unwrap();
1991        let _result = fut.await;
1992
1993        assert_eq!(rx.recv().await, Some("0".to_string()));
1994        assert_eq!(rx.recv().await, Some("1".to_string()));
1995        assert_eq!(rx.recv().await, Some("2".to_string()));
1996    }
1997
1998    #[tokio::test]
1999    async fn test_register_stream_with_state() {
2000        struct AppState {
2001            items: Vec<String>,
2002        }
2003
2004        let mut router = Router::new().with_state(AppState {
2005            items: vec!["x".to_string(), "y".to_string()],
2006        });
2007        router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
2008            "state_stream",
2009            |state: State<Arc<AppState>>, _args: serde_json::Value| {
2010                let items = state.items.clone();
2011                async move { tokio_stream::iter(items) }
2012            },
2013        );
2014
2015        assert!(router.is_streaming("state_stream"));
2016    }
2017
2018    #[tokio::test]
2019    async fn test_stream_adapter_shows_in_is_streaming() {
2020        let mut router = Router::new();
2021        router.register_stream("my_stream", || async {
2022            tokio_stream::iter(vec!["done".to_string()])
2023        });
2024
2025        assert!(router.is_streaming("my_stream"));
2026        assert!(!router.is_streaming("nonexistent"));
2027    }
2028
2029    #[tokio::test]
2030    async fn test_multiple_state_types() {
2031        struct DbPool {
2032            url: String,
2033        }
2034        struct AppConfig {
2035            name: String,
2036        }
2037
2038        #[derive(serde::Deserialize)]
2039        struct Input {
2040            key: String,
2041        }
2042
2043        let mut router = Router::new()
2044            .with_state(DbPool {
2045                url: "postgres://localhost".to_string(),
2046            })
2047            .with_state(AppConfig {
2048                name: "MyApp".to_string(),
2049            });
2050
2051        // Handler using DbPool
2052        router.register_with_state::<DbPool, Input, _, _>(
2053            "db_query",
2054            |state: State<Arc<DbPool>>, args: Input| async move {
2055                format!("{}:{}", state.url, args.key)
2056            },
2057        );
2058
2059        // Handler using AppConfig
2060        router.register_with_state_only::<AppConfig, _, _>(
2061            "app_name",
2062            |state: State<Arc<AppConfig>>| async move { state.name.clone() },
2063        );
2064
2065        let result = router.call_handler("db_query", r#"{"key":"users"}"#).await;
2066        assert_eq!(result, Ok("postgres://localhost:users".to_string()));
2067
2068        let result = router.call_handler("app_name", "{}").await;
2069        assert_eq!(result, Ok("MyApp".to_string()));
2070    }
2071
2072    #[tokio::test]
2073    async fn test_inject_state_after_construction() {
2074        struct LateState {
2075            value: String,
2076        }
2077
2078        let mut router = Router::new();
2079        router.inject_state(LateState {
2080            value: "injected".to_string(),
2081        });
2082        router.register_with_state_only::<LateState, _, _>(
2083            "get_value",
2084            |state: State<Arc<LateState>>| async move { state.value.clone() },
2085        );
2086
2087        let result = router.call_handler("get_value", "{}").await;
2088        assert_eq!(result, Ok("injected".to_string()));
2089    }
2090
2091    #[tokio::test]
2092    async fn test_multiple_state_streaming() {
2093        struct StreamConfig {
2094            prefix: String,
2095        }
2096
2097        let mut router = Router::new().with_state(StreamConfig {
2098            prefix: "stream".to_string(),
2099        });
2100
2101        router.register_streaming_with_state_only::<StreamConfig, _, _, _>(
2102            "prefixed_stream",
2103            |state: State<Arc<StreamConfig>>, tx: StreamSender| async move {
2104                tx.send(format!("{}:item", state.prefix)).await.ok();
2105                "done".to_string()
2106            },
2107        );
2108
2109        let (mut rx, fut) = router
2110            .call_streaming_handler("prefixed_stream", "{}")
2111            .unwrap();
2112        let result = fut.await;
2113        assert_eq!(result, Ok("done".to_string()));
2114        assert_eq!(rx.recv().await, Some("stream:item".to_string()));
2115    }
2116
2117    #[tokio::test]
2118    async fn test_with_state_duplicate_type_last_wins() {
2119        // Calling with_state twice with the same type replaces the previous value.
2120        let mut router = Router::new()
2121            .with_state("first".to_string())
2122            .with_state("second".to_string());
2123
2124        router.register_with_state_only::<String, _, _>(
2125            "get",
2126            |state: State<Arc<String>>| async move { (**state).clone() },
2127        );
2128
2129        let result = router.call_handler("get", "{}").await;
2130        assert_eq!(result, Ok("second".to_string()));
2131    }
2132
2133    // ─── register_handlers! macro tests ─────────────────────────────────
2134
2135    // Define handler functions at module scope so they're visible as paths
2136    mod macro_test_handlers {
2137        use super::{State, StreamSender};
2138        use std::sync::Arc;
2139
2140        pub async fn health() -> String {
2141            "ok".to_string()
2142        }
2143
2144        pub async fn echo(args: EchoArgs) -> String {
2145            args.message
2146        }
2147
2148        #[derive(serde::Deserialize)]
2149        pub struct EchoArgs {
2150            pub message: String,
2151        }
2152
2153        pub async fn ticker(tx: StreamSender) -> String {
2154            tx.send("tick".to_string()).await.ok();
2155            "done".to_string()
2156        }
2157
2158        pub async fn search(args: SearchArgs, tx: StreamSender) -> String {
2159            tx.send(format!("found:{}", args.query)).await.ok();
2160            "complete".to_string()
2161        }
2162
2163        #[derive(serde::Deserialize)]
2164        pub struct SearchArgs {
2165            pub query: String,
2166        }
2167
2168        // State handler functions for register_handlers! state variants
2169        pub async fn get_status(state: State<Arc<String>>) -> String {
2170            format!("status:{}", *state)
2171        }
2172
2173        pub async fn save_key(state: State<Arc<String>>, args: SaveArgs) -> String {
2174            format!("{}:{}", *state, args.key)
2175        }
2176
2177        #[derive(serde::Deserialize)]
2178        pub struct SaveArgs {
2179            pub key: String,
2180        }
2181
2182        pub async fn state_stream(state: State<Arc<String>>, tx: StreamSender) -> String {
2183            tx.send(format!("{}:chunk", *state)).await.ok();
2184            "done".to_string()
2185        }
2186
2187        pub async fn state_search(
2188            state: State<Arc<String>>,
2189            args: SearchArgs,
2190            tx: StreamSender,
2191        ) -> String {
2192            tx.send(format!("{}:{}", *state, args.query)).await.ok();
2193            "complete".to_string()
2194        }
2195    }
2196
2197    #[tokio::test]
2198    async fn test_register_handlers_basic() {
2199        let mut router = Router::new();
2200        register_handlers!(router, [
2201            "health" => macro_test_handlers::health,
2202        ]);
2203        assert_eq!(router.handlers_count(), 1);
2204        let result = router.call_handler("health", "{}").await;
2205        assert_eq!(result, Ok("ok".to_string()));
2206    }
2207
2208    #[tokio::test]
2209    async fn test_register_handlers_with_args() {
2210        let mut router = Router::new();
2211        register_handlers!(router, [
2212            args "echo" => macro_test_handlers::echo,
2213        ]);
2214        assert_eq!(router.handlers_count(), 1);
2215        let result = router
2216            .call_handler("echo", r#"{"message":"hello"}"#)
2217            .await;
2218        assert_eq!(result, Ok("hello".to_string()));
2219    }
2220
2221    #[tokio::test]
2222    async fn test_register_handlers_streaming() {
2223        let mut router = Router::new();
2224        register_handlers!(router, [
2225            streaming "ticker" => macro_test_handlers::ticker,
2226        ]);
2227        assert!(router.is_streaming("ticker"));
2228        let (mut rx, fut) = router.call_streaming_handler("ticker", "{}").unwrap();
2229        let result = fut.await;
2230        assert_eq!(result, Ok("done".to_string()));
2231        assert_eq!(rx.recv().await, Some("tick".to_string()));
2232    }
2233
2234    #[tokio::test]
2235    async fn test_register_handlers_streaming_with_args() {
2236        let mut router = Router::new();
2237        register_handlers!(router, [
2238            streaming args "search" => macro_test_handlers::search,
2239        ]);
2240        assert!(router.is_streaming("search"));
2241        let (mut rx, fut) = router
2242            .call_streaming_handler("search", r#"{"query":"rust"}"#)
2243            .unwrap();
2244        let result = fut.await;
2245        assert_eq!(result, Ok("complete".to_string()));
2246        assert_eq!(rx.recv().await, Some("found:rust".to_string()));
2247    }
2248
2249    #[tokio::test]
2250    async fn test_register_handlers_mixed() {
2251        let mut router = Router::new();
2252        register_handlers!(router, [
2253            "health" => macro_test_handlers::health,
2254            args "echo" => macro_test_handlers::echo,
2255            streaming "ticker" => macro_test_handlers::ticker,
2256            streaming args "search" => macro_test_handlers::search,
2257        ]);
2258
2259        // All 4 registered (2 regular + 2 streaming)
2260        assert_eq!(router.handlers_count(), 2);
2261        assert_eq!(router.list_handlers().len(), 4);
2262
2263        // Regular handlers work
2264        assert_eq!(
2265            router.call_handler("health", "{}").await,
2266            Ok("ok".to_string())
2267        );
2268        assert_eq!(
2269            router
2270                .call_handler("echo", r#"{"message":"hi"}"#)
2271                .await,
2272            Ok("hi".to_string())
2273        );
2274
2275        // Streaming handlers work
2276        assert!(router.is_streaming("ticker"));
2277        assert!(router.is_streaming("search"));
2278    }
2279
2280    #[tokio::test]
2281    async fn test_register_handlers_empty() {
2282        let router = Router::new();
2283        register_handlers!(router, []);
2284        assert_eq!(router.handlers_count(), 0);
2285    }
2286
2287    #[tokio::test]
2288    async fn test_register_handlers_state_only() {
2289        let mut router = Router::new().with_state("active".to_string());
2290        register_handlers!(router, [
2291            state "get_status" => macro_test_handlers::get_status,
2292        ]);
2293        let result = router.call_handler("get_status", "{}").await;
2294        assert_eq!(result, Ok("status:active".to_string()));
2295    }
2296
2297    #[tokio::test]
2298    async fn test_register_handlers_state_args() {
2299        let mut router = Router::new().with_state("ns".to_string());
2300        register_handlers!(router, [
2301            state args "save_key" => macro_test_handlers::save_key,
2302        ]);
2303        let result = router
2304            .call_handler("save_key", r#"{"key":"api_token"}"#)
2305            .await;
2306        assert_eq!(result, Ok("ns:api_token".to_string()));
2307    }
2308
2309    #[tokio::test]
2310    async fn test_register_handlers_state_streaming() {
2311        let mut router = Router::new().with_state("ctx".to_string());
2312        register_handlers!(router, [
2313            state streaming "state_stream" => macro_test_handlers::state_stream,
2314        ]);
2315        assert!(router.is_streaming("state_stream"));
2316        let (mut rx, fut) = router
2317            .call_streaming_handler("state_stream", "{}")
2318            .unwrap();
2319        let result = fut.await;
2320        assert_eq!(result, Ok("done".to_string()));
2321        assert_eq!(rx.recv().await, Some("ctx:chunk".to_string()));
2322    }
2323
2324    #[tokio::test]
2325    async fn test_register_handlers_state_streaming_args() {
2326        let mut router = Router::new().with_state("db".to_string());
2327        register_handlers!(router, [
2328            state streaming args "state_search" => macro_test_handlers::state_search,
2329        ]);
2330        assert!(router.is_streaming("state_search"));
2331        let (mut rx, fut) = router
2332            .call_streaming_handler("state_search", r#"{"query":"rust"}"#)
2333            .unwrap();
2334        let result = fut.await;
2335        assert_eq!(result, Ok("complete".to_string()));
2336        assert_eq!(rx.recv().await, Some("db:rust".to_string()));
2337    }
2338
2339    #[tokio::test]
2340    async fn test_register_handlers_mixed_with_state() {
2341        let mut router = Router::new().with_state("app".to_string());
2342        register_handlers!(router, [
2343            "health" => macro_test_handlers::health,
2344            args "echo" => macro_test_handlers::echo,
2345            state "get_status" => macro_test_handlers::get_status,
2346            state args "save_key" => macro_test_handlers::save_key,
2347            streaming "ticker" => macro_test_handlers::ticker,
2348            state streaming "state_stream" => macro_test_handlers::state_stream,
2349            state streaming args "state_search" => macro_test_handlers::state_search,
2350        ]);
2351
2352        // Regular handlers
2353        assert_eq!(
2354            router.call_handler("health", "{}").await,
2355            Ok("ok".to_string())
2356        );
2357        assert_eq!(
2358            router.call_handler("get_status", "{}").await,
2359            Ok("status:app".to_string())
2360        );
2361        assert_eq!(
2362            router
2363                .call_handler("save_key", r#"{"key":"secret"}"#)
2364                .await,
2365            Ok("app:secret".to_string())
2366        );
2367
2368        // Streaming handlers
2369        assert!(router.is_streaming("ticker"));
2370        assert!(router.is_streaming("state_stream"));
2371        assert!(router.is_streaming("state_search"));
2372    }
2373}