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/// ```
1028///
1029/// # Expands to
1030///
1031/// ```rust,ignore
1032/// router.register("health", health_check);
1033/// router.register_with_args("greet", greet);
1034/// router.register_streaming("feed", live_feed);
1035/// router.register_streaming_with_args("search", search_stream);
1036/// ```
1037///
1038/// # Why this helps
1039///
1040/// When handler functions are defined in separate modules and only called via
1041/// `router.register("name", || async { handler().await })`, the compiler
1042/// cannot always trace the usage chain and reports `dead_code` warnings.
1043/// This macro passes each function directly as a function item, making the
1044/// reference visible to `rustc`'s dead-code analysis.
1045#[macro_export]
1046macro_rules! register_handlers {
1047    ($router:expr, [ $($entry:tt)* ]) => {
1048        $crate::register_handlers!(@entries $router, $($entry)*)
1049    };
1050
1051    // Terminal case
1052    (@entries $router:expr, ) => {};
1053
1054    // Basic: "name" => handler,
1055    (@entries $router:expr, $name:literal => $handler:path, $($rest:tt)*) => {
1056        $router.register($name, $handler);
1057        $crate::register_handlers!(@entries $router, $($rest)*)
1058    };
1059
1060    // With args: args "name" => handler,
1061    (@entries $router:expr, args $name:literal => $handler:path, $($rest:tt)*) => {
1062        $router.register_with_args($name, $handler);
1063        $crate::register_handlers!(@entries $router, $($rest)*)
1064    };
1065
1066    // Streaming: streaming "name" => handler,
1067    (@entries $router:expr, streaming $name:literal => $handler:path, $($rest:tt)*) => {
1068        $router.register_streaming($name, $handler);
1069        $crate::register_handlers!(@entries $router, $($rest)*)
1070    };
1071
1072    // Streaming with args: streaming args "name" => handler,
1073    (@entries $router:expr, streaming args $name:literal => $handler:path, $($rest:tt)*) => {
1074        $router.register_streaming_with_args($name, $handler);
1075        $crate::register_handlers!(@entries $router, $($rest)*)
1076    };
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081    use super::*;
1082
1083    #[tokio::test]
1084    async fn test_router_creation() {
1085        let router = Router::new();
1086        assert_eq!(router.handlers_count(), 0);
1087    }
1088
1089    #[tokio::test]
1090    async fn test_handler_registration() {
1091        let mut router = Router::new();
1092        router.register("test", || async { "Hello".to_string() });
1093        assert_eq!(router.handlers_count(), 1);
1094    }
1095
1096    #[tokio::test]
1097    async fn test_handler_execution() {
1098        let mut router = Router::new();
1099        router.register("test", || async { "Hello".to_string() });
1100        let result = router.execute("test").await;
1101        assert_eq!(result, Ok("Hello".to_string()));
1102    }
1103
1104    // New tests for route metadata tracking
1105    #[tokio::test]
1106    async fn test_router_starts_with_no_routes() {
1107        let router = Router::new();
1108        let routes = router.routes();
1109        assert_eq!(routes.len(), 0);
1110    }
1111
1112    #[tokio::test]
1113    async fn test_add_route_metadata() {
1114        let mut router = Router::new();
1115        let metadata = RouteMetadata::new("/users", "GET", "rest");
1116
1117        router.add_route(metadata.clone());
1118
1119        let routes = router.routes();
1120        assert_eq!(routes.len(), 1);
1121        assert_eq!(routes[0].path, "/users");
1122        assert_eq!(routes[0].method, "GET");
1123        assert_eq!(routes[0].protocol, "rest");
1124    }
1125
1126    #[tokio::test]
1127    async fn test_add_multiple_routes() {
1128        let mut router = Router::new();
1129
1130        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1131        router.add_route(RouteMetadata::new("/users", "POST", "rest"));
1132        router.add_route(RouteMetadata::new("/posts", "GET", "rest"));
1133
1134        let routes = router.routes();
1135        assert_eq!(routes.len(), 3);
1136    }
1137
1138    #[tokio::test]
1139    async fn test_routes_with_different_protocols() {
1140        let mut router = Router::new();
1141
1142        router.add_route(RouteMetadata::new("/users", "GET", "rest"));
1143        router.add_route(RouteMetadata::new("users", "query", "graphql"));
1144        router.add_route(RouteMetadata::new("UserService.GetUser", "unary", "grpc"));
1145
1146        let routes = router.routes();
1147        assert_eq!(routes.len(), 3);
1148
1149        assert_eq!(routes[0].protocol, "rest");
1150        assert_eq!(routes[1].protocol, "graphql");
1151        assert_eq!(routes[2].protocol, "grpc");
1152    }
1153
1154    #[tokio::test]
1155    async fn test_routes_returns_immutable_reference() {
1156        let mut router = Router::new();
1157        router.add_route(RouteMetadata::new("/test", "GET", "rest"));
1158
1159        let routes1 = router.routes();
1160        let routes2 = router.routes();
1161
1162        // Both should have the same data
1163        assert_eq!(routes1.len(), routes2.len());
1164        assert_eq!(routes1[0].path, routes2[0].path);
1165    }
1166
1167    // Tests for type-safe route registration
1168    #[tokio::test]
1169    async fn test_route_get_method() {
1170        let mut router = Router::new();
1171        router.get("/users", || async { "User list".to_string() });
1172
1173        let routes = router.routes();
1174        assert_eq!(routes.len(), 1);
1175        assert_eq!(routes[0].path, "/users");
1176        assert_eq!(routes[0].method, "GET");
1177        assert_eq!(routes[0].protocol, "rest");
1178    }
1179
1180    #[tokio::test]
1181    async fn test_route_post_method() {
1182        let mut router = Router::new();
1183        router.post("/users", || async { "User created".to_string() });
1184
1185        let routes = router.routes();
1186        assert_eq!(routes.len(), 1);
1187        assert_eq!(routes[0].path, "/users");
1188        assert_eq!(routes[0].method, "POST");
1189        assert_eq!(routes[0].protocol, "rest");
1190    }
1191
1192    #[tokio::test]
1193    async fn test_route_put_method() {
1194        let mut router = Router::new();
1195        router.put("/users/1", || async { "User updated".to_string() });
1196
1197        let routes = router.routes();
1198        assert_eq!(routes.len(), 1);
1199        assert_eq!(routes[0].method, "PUT");
1200    }
1201
1202    #[tokio::test]
1203    async fn test_route_delete_method() {
1204        let mut router = Router::new();
1205        router.delete("/users/1", || async { "User deleted".to_string() });
1206
1207        let routes = router.routes();
1208        assert_eq!(routes.len(), 1);
1209        assert_eq!(routes[0].method, "DELETE");
1210    }
1211
1212    #[tokio::test]
1213    async fn test_route_patch_method() {
1214        let mut router = Router::new();
1215        router.patch("/users/1", || async { "User patched".to_string() });
1216
1217        let routes = router.routes();
1218        assert_eq!(routes.len(), 1);
1219        assert_eq!(routes[0].method, "PATCH");
1220    }
1221
1222    #[tokio::test]
1223    async fn test_multiple_routes_different_methods() {
1224        let mut router = Router::new();
1225        router.get("/users", || async { "List".to_string() });
1226        router.post("/users", || async { "Create".to_string() });
1227        router.put("/users/1", || async { "Update".to_string() });
1228        router.delete("/users/1", || async { "Delete".to_string() });
1229
1230        let routes = router.routes();
1231        assert_eq!(routes.len(), 4);
1232
1233        assert_eq!(routes[0].method, "GET");
1234        assert_eq!(routes[1].method, "POST");
1235        assert_eq!(routes[2].method, "PUT");
1236        assert_eq!(routes[3].method, "DELETE");
1237    }
1238
1239    #[tokio::test]
1240    async fn test_route_method_with_path_params() {
1241        let mut router = Router::new();
1242        router.get("/users/{id}", || async { "User details".to_string() });
1243        router.get("/users/{id}/posts/{post_id}", || async {
1244            "Post details".to_string()
1245        });
1246
1247        let routes = router.routes();
1248        assert_eq!(routes.len(), 2);
1249        assert_eq!(routes[0].path, "/users/{id}");
1250        assert_eq!(routes[1].path, "/users/{id}/posts/{post_id}");
1251    }
1252
1253    #[tokio::test]
1254    async fn test_route_registration_and_execution() {
1255        let mut router = Router::new();
1256        router.get("/test", || async { "GET response".to_string() });
1257        router.post("/test", || async { "POST response".to_string() });
1258
1259        // Both route metadata and handler should be registered
1260        assert_eq!(router.routes().len(), 2);
1261        assert_eq!(router.handlers_count(), 2);
1262
1263        // Handlers should be executable
1264        let result1 = router.execute("GET:/test").await;
1265        let result2 = router.execute("POST:/test").await;
1266
1267        assert_eq!(result1, Ok("GET response".to_string()));
1268        assert_eq!(result2, Ok("POST response".to_string()));
1269    }
1270
1271    // Tests for Scalar integration
1272    #[tokio::test]
1273    async fn test_scalar_generates_html() {
1274        let mut router = Router::new();
1275        router.get("/users", || async { "Users".to_string() });
1276
1277        let html = router.scalar("Test API", "1.0.0");
1278
1279        assert!(html.contains("<!DOCTYPE html>"));
1280        assert!(html.contains("<title>Test API - API Documentation</title>"));
1281        assert!(html.contains("@scalar/api-reference"));
1282    }
1283
1284    #[tokio::test]
1285    async fn test_scalar_contains_openapi_spec() {
1286        let mut router = Router::new();
1287        router.get("/users", || async { "Users".to_string() });
1288        router.post("/users", || async { "User created".to_string() });
1289
1290        let html = router.scalar("Test API", "1.0.0");
1291
1292        // Should contain the OpenAPI spec
1293        assert!(html.contains("openapi"));
1294        assert!(html.contains("Test API"));
1295        assert!(html.contains("1.0.0"));
1296    }
1297
1298    #[tokio::test]
1299    async fn test_scalar_docs_with_custom_config() {
1300        let mut router = Router::new();
1301        router.get("/users", || async { "Users".to_string() });
1302
1303        let config = scalar::ScalarConfig::new()
1304            .theme(scalar::ScalarTheme::Light)
1305            .show_sidebar(false);
1306
1307        let html = router.scalar_docs(config, "Custom API", "2.0.0");
1308
1309        assert!(html.contains("Custom API"));
1310        assert!(html.contains(r#""theme":"light""#));
1311        assert!(html.contains(r#""showSidebar":false"#));
1312    }
1313
1314    #[tokio::test]
1315    async fn test_scalar_docs_with_custom_css() {
1316        let mut router = Router::new();
1317        router.get("/test", || async { "Test".to_string() });
1318
1319        let config = scalar::ScalarConfig::new().custom_css("body { font-family: 'Inter'; }");
1320
1321        let html = router.scalar_docs(config, "API", "1.0");
1322
1323        assert!(html.contains("<style>body { font-family: 'Inter'; }</style>"));
1324    }
1325
1326    #[tokio::test]
1327    async fn test_scalar_with_multiple_routes() {
1328        let mut router = Router::new();
1329        router.get("/users", || async { "Users".to_string() });
1330        router.post("/users", || async { "Create".to_string() });
1331        router.get("/users/{id}", || async { "User details".to_string() });
1332        router.delete("/users/{id}", || async { "Delete".to_string() });
1333
1334        let html = router.scalar("API", "1.0.0");
1335
1336        // Should contain all routes in the OpenAPI spec
1337        assert!(html.contains("/users"));
1338    }
1339
1340    // Tests for protocol adapter management
1341    #[tokio::test]
1342    async fn test_get_adapter_returns_adapter() {
1343        let mut router = Router::new();
1344        router.add_adapter(Box::new(RestAdapter::new()));
1345
1346        let adapter = router.get_adapter("rest");
1347        assert!(adapter.is_some());
1348        assert_eq!(adapter.unwrap().name(), "rest");
1349    }
1350
1351    #[tokio::test]
1352    async fn test_get_adapter_returns_none_for_missing() {
1353        let router = Router::new();
1354        let adapter = router.get_adapter("rest");
1355        assert!(adapter.is_none());
1356    }
1357
1358    #[tokio::test]
1359    async fn test_route_request_success() {
1360        let mut router = Router::new();
1361        router.register("test_handler", || async { "Success!".to_string() });
1362
1363        // Register adapter with a route
1364        let mut rest_adapter = RestAdapter::new();
1365        rest_adapter.route("GET", "/test", "test_handler");
1366        router.add_adapter(Box::new(rest_adapter));
1367
1368        let result = router.route_request("rest", "GET /test").await;
1369        assert!(result.is_ok());
1370        let response = result.unwrap();
1371        assert!(response.contains("HTTP 200") || response.contains("test_handler"));
1372    }
1373
1374    #[tokio::test]
1375    async fn test_route_request_unknown_adapter() {
1376        let router = Router::new();
1377        let result = router.route_request("unknown", "test").await;
1378        assert!(result.is_err());
1379        assert!(result.unwrap_err().contains("Adapter not found"));
1380    }
1381
1382    #[tokio::test]
1383    async fn test_enabled_protocols_empty() {
1384        let router = Router::new();
1385        let protocols = router.enabled_protocols();
1386        assert_eq!(protocols.len(), 0);
1387    }
1388
1389    #[tokio::test]
1390    async fn test_enabled_protocols_multiple() {
1391        let mut router = Router::new();
1392        router.add_adapter(Box::new(RestAdapter::new()));
1393        router.add_adapter(Box::new(GraphQLAdapter::new()));
1394        router.add_adapter(Box::new(GrpcAdapter::new()));
1395
1396        let protocols = router.enabled_protocols();
1397        assert_eq!(protocols.len(), 3);
1398        assert!(protocols.contains(&"rest".to_string()));
1399        assert!(protocols.contains(&"graphql".to_string()));
1400        assert!(protocols.contains(&"grpc".to_string()));
1401    }
1402
1403    #[tokio::test]
1404    async fn test_can_handle_rest() {
1405        let mut router = Router::new();
1406        assert!(!router.can_handle_rest("test"));
1407
1408        router.add_adapter(Box::new(RestAdapter::new()));
1409        assert!(router.can_handle_rest("test"));
1410    }
1411
1412    #[tokio::test]
1413    async fn test_can_handle_graphql() {
1414        let mut router = Router::new();
1415        assert!(!router.can_handle_graphql("test"));
1416
1417        router.add_adapter(Box::new(GraphQLAdapter::new()));
1418        assert!(router.can_handle_graphql("test"));
1419    }
1420
1421    #[tokio::test]
1422    async fn test_can_handle_grpc() {
1423        let mut router = Router::new();
1424        assert!(!router.can_handle_grpc("test"));
1425
1426        router.add_adapter(Box::new(GrpcAdapter::new()));
1427        assert!(router.can_handle_grpc("test"));
1428    }
1429
1430    // ===== Integration Tests: Multi-Protocol Routing =====
1431
1432    #[tokio::test]
1433    async fn test_integration_single_handler_rest() {
1434        // Test: Single handler exposed via REST
1435        let mut router = Router::new();
1436        router.register("get_user", || async { "User data".to_string() });
1437
1438        // Configure REST adapter
1439        let mut rest = RestAdapter::new();
1440        rest.route("GET", "/users/:id", "get_user");
1441        router.add_adapter(Box::new(rest));
1442
1443        // Route REST request
1444        let response = router.route_request("rest", "GET /users/42").await;
1445        assert!(response.is_ok());
1446        assert!(response.unwrap().contains("get_user"));
1447    }
1448
1449    #[tokio::test]
1450    async fn test_integration_single_handler_graphql() {
1451        // Test: Single handler exposed via GraphQL
1452        let mut router = Router::new();
1453        router.register("get_user", || async { "User data".to_string() });
1454
1455        // Configure GraphQL adapter
1456        let mut graphql = GraphQLAdapter::new();
1457        graphql.query("user", "get_user");
1458        router.add_adapter(Box::new(graphql));
1459
1460        // Route GraphQL request
1461        let response = router.route_request("graphql", "query { user }").await;
1462        assert!(response.is_ok());
1463        assert!(response.unwrap().contains("get_user"));
1464    }
1465
1466    #[tokio::test]
1467    async fn test_integration_single_handler_grpc() {
1468        // Test: Single handler exposed via gRPC
1469        let mut router = Router::new();
1470        router.register("get_user", || async { "User data".to_string() });
1471
1472        // Configure gRPC adapter
1473        let mut grpc = GrpcAdapter::new();
1474        grpc.unary("UserService", "GetUser", "get_user");
1475        router.add_adapter(Box::new(grpc));
1476
1477        // Route gRPC request
1478        let response = router
1479            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1480            .await;
1481        assert!(response.is_ok());
1482        assert!(response.unwrap().contains("get_user"));
1483    }
1484
1485    #[tokio::test]
1486    async fn test_integration_single_handler_all_protocols() {
1487        // Test: Single handler exposed via ALL protocols
1488        let mut router = Router::new();
1489        router.register("get_user", || async { "User data".to_string() });
1490
1491        // Configure REST adapter
1492        let mut rest = RestAdapter::new();
1493        rest.route("GET", "/users/:id", "get_user");
1494        router.add_adapter(Box::new(rest));
1495
1496        // Configure GraphQL adapter
1497        let mut graphql = GraphQLAdapter::new();
1498        graphql.query("user", "get_user");
1499        router.add_adapter(Box::new(graphql));
1500
1501        // Configure gRPC adapter
1502        let mut grpc = GrpcAdapter::new();
1503        grpc.unary("UserService", "GetUser", "get_user");
1504        router.add_adapter(Box::new(grpc));
1505
1506        // Test REST
1507        let rest_response = router.route_request("rest", "GET /users/42").await;
1508        assert!(rest_response.is_ok());
1509        assert!(rest_response.unwrap().contains("get_user"));
1510
1511        // Test GraphQL
1512        let graphql_response = router.route_request("graphql", "query { user }").await;
1513        assert!(graphql_response.is_ok());
1514        assert!(graphql_response.unwrap().contains("get_user"));
1515
1516        // Test gRPC
1517        let grpc_response = router
1518            .route_request("grpc", "UserService.GetUser:{\"id\":42}")
1519            .await;
1520        assert!(grpc_response.is_ok());
1521        assert!(grpc_response.unwrap().contains("get_user"));
1522    }
1523
1524    #[tokio::test]
1525    async fn test_integration_multiple_handlers_all_protocols() {
1526        // Test: Multiple handlers, each exposed via all protocols
1527        let mut router = Router::new();
1528        router.register("get_user", || async { "User data".to_string() });
1529        router.register("list_users", || async { "Users list".to_string() });
1530        router.register("create_user", || async { "Created user".to_string() });
1531
1532        // Configure REST adapter
1533        let mut rest = RestAdapter::new();
1534        rest.route("GET", "/users/:id", "get_user");
1535        rest.route("GET", "/users", "list_users");
1536        rest.route("POST", "/users", "create_user");
1537        router.add_adapter(Box::new(rest));
1538
1539        // Configure GraphQL adapter
1540        let mut graphql = GraphQLAdapter::new();
1541        graphql.query("user", "get_user");
1542        graphql.query("users", "list_users");
1543        graphql.mutation("createUser", "create_user");
1544        router.add_adapter(Box::new(graphql));
1545
1546        // Configure gRPC adapter
1547        let mut grpc = GrpcAdapter::new();
1548        grpc.unary("UserService", "GetUser", "get_user");
1549        grpc.unary("UserService", "ListUsers", "list_users");
1550        grpc.unary("UserService", "CreateUser", "create_user");
1551        router.add_adapter(Box::new(grpc));
1552
1553        // Test each handler via each protocol
1554        assert!(router
1555            .route_request("rest", "GET /users/42")
1556            .await
1557            .unwrap()
1558            .contains("get_user"));
1559        assert!(router
1560            .route_request("graphql", "query { user }")
1561            .await
1562            .unwrap()
1563            .contains("get_user"));
1564        assert!(router
1565            .route_request("grpc", "UserService.GetUser:{}")
1566            .await
1567            .unwrap()
1568            .contains("get_user"));
1569    }
1570
1571    #[tokio::test]
1572    async fn test_integration_error_handling_rest_404() {
1573        // Test: REST 404 error
1574        let mut router = Router::new();
1575
1576        let mut rest = RestAdapter::new();
1577        rest.route("GET", "/users/:id", "get_user");
1578        router.add_adapter(Box::new(rest));
1579
1580        let response = router.route_request("rest", "GET /posts/42").await;
1581        assert!(response.is_ok());
1582        assert!(response.unwrap().contains("HTTP 404"));
1583    }
1584
1585    #[tokio::test]
1586    async fn test_integration_error_handling_graphql_not_found() {
1587        // Test: GraphQL operation not found
1588        let mut router = Router::new();
1589
1590        let mut graphql = GraphQLAdapter::new();
1591        graphql.query("user", "get_user");
1592        router.add_adapter(Box::new(graphql));
1593
1594        let response = router.route_request("graphql", "query { post }").await;
1595        assert!(response.is_ok());
1596        assert!(response.unwrap().contains("errors"));
1597    }
1598
1599    #[tokio::test]
1600    async fn test_integration_error_handling_grpc_unimplemented() {
1601        // Test: gRPC method not implemented
1602        let mut router = Router::new();
1603
1604        let mut grpc = GrpcAdapter::new();
1605        grpc.unary("UserService", "GetUser", "get_user");
1606        router.add_adapter(Box::new(grpc));
1607
1608        let response = router.route_request("grpc", "UserService.GetPost:{}").await;
1609        assert!(response.is_ok());
1610        assert!(response.unwrap().contains("grpc-status: 12")); // UNIMPLEMENTED
1611    }
1612
1613    #[tokio::test]
1614    async fn test_integration_unknown_protocol() {
1615        // Test: Unknown protocol error
1616        let router = Router::new();
1617
1618        let response = router.route_request("unknown", "request").await;
1619        assert!(response.is_err());
1620        assert!(response.unwrap_err().contains("Adapter not found"));
1621    }
1622
1623    #[tokio::test]
1624    async fn test_integration_protocol_specific_features_rest_methods() {
1625        // Test: REST-specific HTTP methods
1626        let mut router = Router::new();
1627        router.register("get_users", || async { "Users".to_string() });
1628        router.register("create_user", || async { "Created".to_string() });
1629        router.register("update_user", || async { "Updated".to_string() });
1630        router.register("delete_user", || async { "Deleted".to_string() });
1631
1632        let mut rest = RestAdapter::new();
1633        rest.route("GET", "/users", "get_users");
1634        rest.route("POST", "/users", "create_user");
1635        rest.route("PUT", "/users/:id", "update_user");
1636        rest.route("DELETE", "/users/:id", "delete_user");
1637        router.add_adapter(Box::new(rest));
1638
1639        // Test different HTTP methods
1640        assert!(router
1641            .route_request("rest", "GET /users")
1642            .await
1643            .unwrap()
1644            .contains("get_users"));
1645        assert!(router
1646            .route_request("rest", "POST /users")
1647            .await
1648            .unwrap()
1649            .contains("create_user"));
1650        assert!(router
1651            .route_request("rest", "PUT /users/42")
1652            .await
1653            .unwrap()
1654            .contains("update_user"));
1655        assert!(router
1656            .route_request("rest", "DELETE /users/42")
1657            .await
1658            .unwrap()
1659            .contains("delete_user"));
1660    }
1661
1662    #[tokio::test]
1663    async fn test_integration_protocol_specific_features_graphql_types() {
1664        // Test: GraphQL-specific query vs mutation
1665        let mut router = Router::new();
1666        router.register("get_user", || async { "User".to_string() });
1667        router.register("create_user", || async { "Created".to_string() });
1668
1669        let mut graphql = GraphQLAdapter::new();
1670        graphql.query("user", "get_user");
1671        graphql.mutation("createUser", "create_user");
1672        router.add_adapter(Box::new(graphql));
1673
1674        // Test query
1675        assert!(router
1676            .route_request("graphql", "query { user }")
1677            .await
1678            .unwrap()
1679            .contains("get_user"));
1680
1681        // Test mutation
1682        assert!(router
1683            .route_request("graphql", "mutation { createUser }")
1684            .await
1685            .unwrap()
1686            .contains("create_user"));
1687    }
1688
1689    #[tokio::test]
1690    async fn test_integration_protocol_specific_features_grpc_streaming() {
1691        // Test: gRPC-specific streaming modes
1692        let mut router = Router::new();
1693        router.register("get_user", || async { "User".to_string() });
1694        router.register("list_users", || async { "Users".to_string() });
1695
1696        let mut grpc = GrpcAdapter::new();
1697        grpc.unary("UserService", "GetUser", "get_user");
1698        grpc.server_streaming("UserService", "ListUsers", "list_users");
1699        router.add_adapter(Box::new(grpc));
1700
1701        // Test unary
1702        let unary_response = router
1703            .route_request("grpc", "UserService.GetUser:{}")
1704            .await
1705            .unwrap();
1706        assert!(unary_response.contains("unary"));
1707
1708        // Test server streaming
1709        let streaming_response = router
1710            .route_request("grpc", "UserService.ListUsers:{}")
1711            .await
1712            .unwrap();
1713        assert!(streaming_response.contains("server_streaming"));
1714    }
1715
1716    // ===== Streaming handler registration tests =====
1717
1718    #[tokio::test]
1719    async fn test_register_streaming_handler() {
1720        let mut router = Router::new();
1721        router.register_streaming("stream_data", |tx: StreamSender| async move {
1722            tx.send("item".to_string()).await.ok();
1723            "done".to_string()
1724        });
1725        assert!(router.is_streaming("stream_data"));
1726        assert!(!router.is_streaming("nonexistent"));
1727    }
1728
1729    #[tokio::test]
1730    async fn test_register_streaming_with_args() {
1731        #[derive(serde::Deserialize)]
1732        struct Input {
1733            count: usize,
1734        }
1735
1736        let mut router = Router::new();
1737        router.register_streaming_with_args("stream_items", |args: Input, tx: StreamSender| async move {
1738            for i in 0..args.count {
1739                tx.send(format!("item-{i}")).await.ok();
1740            }
1741            "done".to_string()
1742        });
1743        assert!(router.is_streaming("stream_items"));
1744    }
1745
1746    #[tokio::test]
1747    async fn test_streaming_handler_not_in_regular_handlers() {
1748        let mut router = Router::new();
1749        router.register_streaming("stream", |_tx: StreamSender| async move {
1750            "done".to_string()
1751        });
1752        // Streaming handlers are NOT in the regular handlers map
1753        assert_eq!(router.handlers_count(), 0);
1754    }
1755
1756    #[tokio::test]
1757    async fn test_list_handlers_includes_streaming() {
1758        let mut router = Router::new();
1759        router.register("regular", || async { "ok".to_string() });
1760        router.register_streaming("stream", |_tx: StreamSender| async move {
1761            "ok".to_string()
1762        });
1763
1764        let handlers = router.list_handlers();
1765        assert_eq!(handlers.len(), 2);
1766        assert!(handlers.contains(&"regular".to_string()));
1767        assert!(handlers.contains(&"stream".to_string()));
1768    }
1769
1770    #[tokio::test]
1771    async fn test_call_streaming_handler() {
1772        let mut router = Router::new();
1773        router.register_streaming("stream", |tx: StreamSender| async move {
1774            tx.send("a".to_string()).await.ok();
1775            tx.send("b".to_string()).await.ok();
1776            "final".to_string()
1777        });
1778
1779        let (mut rx, fut) = router.call_streaming_handler("stream", "{}").unwrap();
1780        let result = fut.await;
1781
1782        assert_eq!(result, Ok("final".to_string()));
1783        assert_eq!(rx.recv().await, Some("a".to_string()));
1784        assert_eq!(rx.recv().await, Some("b".to_string()));
1785    }
1786
1787    #[tokio::test]
1788    async fn test_call_streaming_handler_with_args() {
1789        #[derive(serde::Deserialize)]
1790        struct Input {
1791            n: usize,
1792        }
1793
1794        let mut router = Router::new();
1795        router.register_streaming_with_args("count", |args: Input, tx: StreamSender| async move {
1796            for i in 0..args.n {
1797                tx.send(format!("{i}")).await.ok();
1798            }
1799            format!("counted to {}", args.n)
1800        });
1801
1802        let (mut rx, fut) = router.call_streaming_handler("count", r#"{"n":3}"#).unwrap();
1803        let result = fut.await;
1804
1805        assert_eq!(result, Ok("counted to 3".to_string()));
1806        assert_eq!(rx.recv().await, Some("0".to_string()));
1807        assert_eq!(rx.recv().await, Some("1".to_string()));
1808        assert_eq!(rx.recv().await, Some("2".to_string()));
1809    }
1810
1811    #[tokio::test]
1812    async fn test_call_streaming_handler_not_found() {
1813        let router = Router::new();
1814        let result = router.call_streaming_handler("missing", "{}");
1815        assert!(result.is_err());
1816        match result {
1817            Err(e) => assert!(e.contains("not found")),
1818            Ok(_) => panic!("expected error"),
1819        }
1820    }
1821
1822    #[tokio::test]
1823    async fn test_is_streaming_false_for_regular() {
1824        let mut router = Router::new();
1825        router.register("regular", || async { "ok".to_string() });
1826        assert!(!router.is_streaming("regular"));
1827    }
1828
1829    #[tokio::test]
1830    async fn test_mixed_router() {
1831        let mut router = Router::new();
1832        router.register("get_user", || async { "user".to_string() });
1833        router.register_streaming("stream_updates", |tx: StreamSender| async move {
1834            tx.send("update".to_string()).await.ok();
1835            "done".to_string()
1836        });
1837
1838        // Regular handler works
1839        let result = router.execute("get_user").await;
1840        assert_eq!(result, Ok("user".to_string()));
1841
1842        // Streaming handler works
1843        let (mut rx, fut) = router.call_streaming_handler("stream_updates", "{}").unwrap();
1844        let result = fut.await;
1845        assert_eq!(result, Ok("done".to_string()));
1846        assert_eq!(rx.recv().await, Some("update".to_string()));
1847
1848        // Regular handler not found in streaming
1849        assert!(!router.is_streaming("get_user"));
1850        assert!(router.call_streaming_handler("get_user", "{}").is_err());
1851    }
1852
1853    #[tokio::test]
1854    async fn test_register_streaming_with_state() {
1855        struct AppState {
1856            prefix: String,
1857        }
1858
1859        #[derive(serde::Deserialize)]
1860        struct Input {
1861            name: String,
1862        }
1863
1864        let mut router = Router::new().with_state(AppState {
1865            prefix: "Hello".to_string(),
1866        });
1867        router.register_streaming_with_state::<AppState, Input, _, _, _>(
1868            "greet_stream",
1869            |state: State<Arc<AppState>>, args: Input, tx: StreamSender| async move {
1870                tx.send(format!("{} {}", state.prefix, args.name))
1871                    .await
1872                    .ok();
1873                "done".to_string()
1874            },
1875        );
1876
1877        let (mut rx, fut) = router
1878            .call_streaming_handler("greet_stream", r#"{"name":"Alice"}"#)
1879            .unwrap();
1880        let result = fut.await;
1881
1882        assert_eq!(result, Ok("done".to_string()));
1883        assert_eq!(rx.recv().await, Some("Hello Alice".to_string()));
1884    }
1885
1886    #[tokio::test]
1887    async fn test_register_streaming_with_state_only() {
1888        struct AppState {
1889            items: Vec<String>,
1890        }
1891
1892        let mut router = Router::new().with_state(AppState {
1893            items: vec!["x".to_string(), "y".to_string()],
1894        });
1895        router.register_streaming_with_state_only::<AppState, _, _, _>(
1896            "list_stream",
1897            |state: State<Arc<AppState>>, tx: StreamSender| async move {
1898                for item in &state.items {
1899                    tx.send(item.clone()).await.ok();
1900                }
1901                format!("listed {}", state.items.len())
1902            },
1903        );
1904
1905        let (mut rx, fut) = router
1906            .call_streaming_handler("list_stream", "{}")
1907            .unwrap();
1908        let result = fut.await;
1909
1910        assert_eq!(result, Ok("listed 2".to_string()));
1911        assert_eq!(rx.recv().await, Some("x".to_string()));
1912        assert_eq!(rx.recv().await, Some("y".to_string()));
1913    }
1914
1915    // ===== Stream return adapter tests =====
1916
1917    #[tokio::test]
1918    async fn test_register_stream_no_args() {
1919        let mut router = Router::new();
1920        router.register_stream("items", || async {
1921            tokio_stream::iter(vec!["a".to_string(), "b".to_string(), "c".to_string()])
1922        });
1923
1924        assert!(router.is_streaming("items"));
1925
1926        let (mut rx, fut) = router.call_streaming_handler("items", "{}").unwrap();
1927        let _result = fut.await;
1928
1929        assert_eq!(rx.recv().await, Some("a".to_string()));
1930        assert_eq!(rx.recv().await, Some("b".to_string()));
1931        assert_eq!(rx.recv().await, Some("c".to_string()));
1932    }
1933
1934    #[tokio::test]
1935    async fn test_register_stream_with_args() {
1936        #[derive(serde::Deserialize)]
1937        struct Input {
1938            count: usize,
1939        }
1940
1941        let mut router = Router::new();
1942        router.register_stream_with_args("counting", |args: Input| async move {
1943            tokio_stream::iter((0..args.count).map(|i| format!("{i}")))
1944        });
1945
1946        assert!(router.is_streaming("counting"));
1947
1948        let (mut rx, fut) = router
1949            .call_streaming_handler("counting", r#"{"count":3}"#)
1950            .unwrap();
1951        let _result = fut.await;
1952
1953        assert_eq!(rx.recv().await, Some("0".to_string()));
1954        assert_eq!(rx.recv().await, Some("1".to_string()));
1955        assert_eq!(rx.recv().await, Some("2".to_string()));
1956    }
1957
1958    #[tokio::test]
1959    async fn test_register_stream_with_state() {
1960        struct AppState {
1961            items: Vec<String>,
1962        }
1963
1964        let mut router = Router::new().with_state(AppState {
1965            items: vec!["x".to_string(), "y".to_string()],
1966        });
1967        router.register_stream_with_state::<AppState, serde_json::Value, _, _, _, _>(
1968            "state_stream",
1969            |state: State<Arc<AppState>>, _args: serde_json::Value| {
1970                let items = state.items.clone();
1971                async move { tokio_stream::iter(items) }
1972            },
1973        );
1974
1975        assert!(router.is_streaming("state_stream"));
1976    }
1977
1978    #[tokio::test]
1979    async fn test_stream_adapter_shows_in_is_streaming() {
1980        let mut router = Router::new();
1981        router.register_stream("my_stream", || async {
1982            tokio_stream::iter(vec!["done".to_string()])
1983        });
1984
1985        assert!(router.is_streaming("my_stream"));
1986        assert!(!router.is_streaming("nonexistent"));
1987    }
1988
1989    #[tokio::test]
1990    async fn test_multiple_state_types() {
1991        struct DbPool {
1992            url: String,
1993        }
1994        struct AppConfig {
1995            name: String,
1996        }
1997
1998        #[derive(serde::Deserialize)]
1999        struct Input {
2000            key: String,
2001        }
2002
2003        let mut router = Router::new()
2004            .with_state(DbPool {
2005                url: "postgres://localhost".to_string(),
2006            })
2007            .with_state(AppConfig {
2008                name: "MyApp".to_string(),
2009            });
2010
2011        // Handler using DbPool
2012        router.register_with_state::<DbPool, Input, _, _>(
2013            "db_query",
2014            |state: State<Arc<DbPool>>, args: Input| async move {
2015                format!("{}:{}", state.url, args.key)
2016            },
2017        );
2018
2019        // Handler using AppConfig
2020        router.register_with_state_only::<AppConfig, _, _>(
2021            "app_name",
2022            |state: State<Arc<AppConfig>>| async move { state.name.clone() },
2023        );
2024
2025        let result = router.call_handler("db_query", r#"{"key":"users"}"#).await;
2026        assert_eq!(result, Ok("postgres://localhost:users".to_string()));
2027
2028        let result = router.call_handler("app_name", "{}").await;
2029        assert_eq!(result, Ok("MyApp".to_string()));
2030    }
2031
2032    #[tokio::test]
2033    async fn test_inject_state_after_construction() {
2034        struct LateState {
2035            value: String,
2036        }
2037
2038        let mut router = Router::new();
2039        router.inject_state(LateState {
2040            value: "injected".to_string(),
2041        });
2042        router.register_with_state_only::<LateState, _, _>(
2043            "get_value",
2044            |state: State<Arc<LateState>>| async move { state.value.clone() },
2045        );
2046
2047        let result = router.call_handler("get_value", "{}").await;
2048        assert_eq!(result, Ok("injected".to_string()));
2049    }
2050
2051    #[tokio::test]
2052    async fn test_multiple_state_streaming() {
2053        struct StreamConfig {
2054            prefix: String,
2055        }
2056
2057        let mut router = Router::new().with_state(StreamConfig {
2058            prefix: "stream".to_string(),
2059        });
2060
2061        router.register_streaming_with_state_only::<StreamConfig, _, _, _>(
2062            "prefixed_stream",
2063            |state: State<Arc<StreamConfig>>, tx: StreamSender| async move {
2064                tx.send(format!("{}:item", state.prefix)).await.ok();
2065                "done".to_string()
2066            },
2067        );
2068
2069        let (mut rx, fut) = router
2070            .call_streaming_handler("prefixed_stream", "{}")
2071            .unwrap();
2072        let result = fut.await;
2073        assert_eq!(result, Ok("done".to_string()));
2074        assert_eq!(rx.recv().await, Some("stream:item".to_string()));
2075    }
2076
2077    #[tokio::test]
2078    async fn test_with_state_duplicate_type_last_wins() {
2079        // Calling with_state twice with the same type replaces the previous value.
2080        let mut router = Router::new()
2081            .with_state("first".to_string())
2082            .with_state("second".to_string());
2083
2084        router.register_with_state_only::<String, _, _>(
2085            "get",
2086            |state: State<Arc<String>>| async move { (**state).clone() },
2087        );
2088
2089        let result = router.call_handler("get", "{}").await;
2090        assert_eq!(result, Ok("second".to_string()));
2091    }
2092
2093    // ─── register_handlers! macro tests ─────────────────────────────────
2094
2095    // Define handler functions at module scope so they're visible as paths
2096    mod macro_test_handlers {
2097        use super::StreamSender;
2098
2099        pub async fn health() -> String {
2100            "ok".to_string()
2101        }
2102
2103        pub async fn echo(args: EchoArgs) -> String {
2104            args.message
2105        }
2106
2107        #[derive(serde::Deserialize)]
2108        pub struct EchoArgs {
2109            pub message: String,
2110        }
2111
2112        pub async fn ticker(tx: StreamSender) -> String {
2113            tx.send("tick".to_string()).await.ok();
2114            "done".to_string()
2115        }
2116
2117        pub async fn search(args: SearchArgs, tx: StreamSender) -> String {
2118            tx.send(format!("found:{}", args.query)).await.ok();
2119            "complete".to_string()
2120        }
2121
2122        #[derive(serde::Deserialize)]
2123        pub struct SearchArgs {
2124            pub query: String,
2125        }
2126    }
2127
2128    #[tokio::test]
2129    async fn test_register_handlers_basic() {
2130        let mut router = Router::new();
2131        register_handlers!(router, [
2132            "health" => macro_test_handlers::health,
2133        ]);
2134        assert_eq!(router.handlers_count(), 1);
2135        let result = router.call_handler("health", "{}").await;
2136        assert_eq!(result, Ok("ok".to_string()));
2137    }
2138
2139    #[tokio::test]
2140    async fn test_register_handlers_with_args() {
2141        let mut router = Router::new();
2142        register_handlers!(router, [
2143            args "echo" => macro_test_handlers::echo,
2144        ]);
2145        assert_eq!(router.handlers_count(), 1);
2146        let result = router
2147            .call_handler("echo", r#"{"message":"hello"}"#)
2148            .await;
2149        assert_eq!(result, Ok("hello".to_string()));
2150    }
2151
2152    #[tokio::test]
2153    async fn test_register_handlers_streaming() {
2154        let mut router = Router::new();
2155        register_handlers!(router, [
2156            streaming "ticker" => macro_test_handlers::ticker,
2157        ]);
2158        assert!(router.is_streaming("ticker"));
2159        let (mut rx, fut) = router.call_streaming_handler("ticker", "{}").unwrap();
2160        let result = fut.await;
2161        assert_eq!(result, Ok("done".to_string()));
2162        assert_eq!(rx.recv().await, Some("tick".to_string()));
2163    }
2164
2165    #[tokio::test]
2166    async fn test_register_handlers_streaming_with_args() {
2167        let mut router = Router::new();
2168        register_handlers!(router, [
2169            streaming args "search" => macro_test_handlers::search,
2170        ]);
2171        assert!(router.is_streaming("search"));
2172        let (mut rx, fut) = router
2173            .call_streaming_handler("search", r#"{"query":"rust"}"#)
2174            .unwrap();
2175        let result = fut.await;
2176        assert_eq!(result, Ok("complete".to_string()));
2177        assert_eq!(rx.recv().await, Some("found:rust".to_string()));
2178    }
2179
2180    #[tokio::test]
2181    async fn test_register_handlers_mixed() {
2182        let mut router = Router::new();
2183        register_handlers!(router, [
2184            "health" => macro_test_handlers::health,
2185            args "echo" => macro_test_handlers::echo,
2186            streaming "ticker" => macro_test_handlers::ticker,
2187            streaming args "search" => macro_test_handlers::search,
2188        ]);
2189
2190        // All 4 registered (2 regular + 2 streaming)
2191        assert_eq!(router.handlers_count(), 2);
2192        assert_eq!(router.list_handlers().len(), 4);
2193
2194        // Regular handlers work
2195        assert_eq!(
2196            router.call_handler("health", "{}").await,
2197            Ok("ok".to_string())
2198        );
2199        assert_eq!(
2200            router
2201                .call_handler("echo", r#"{"message":"hi"}"#)
2202                .await,
2203            Ok("hi".to_string())
2204        );
2205
2206        // Streaming handlers work
2207        assert!(router.is_streaming("ticker"));
2208        assert!(router.is_streaming("search"));
2209    }
2210
2211    #[tokio::test]
2212    async fn test_register_handlers_empty() {
2213        let router = Router::new();
2214        register_handlers!(router, []);
2215        assert_eq!(router.handlers_count(), 0);
2216    }
2217}