elif_http/routing/
router.rs

1//! Core routing functionality
2
3use super::{HttpMethod, RouteInfo, RouteRegistry};
4use crate::controller::{factory::IocControllable, ElifController};
5use crate::errors::HttpResult;
6use crate::handlers::elif_handler;
7use crate::middleware::v2::{Middleware, MiddlewarePipelineV2};
8use crate::request::ElifRequest;
9use crate::response::{ElifResponse, IntoElifResponse};
10use axum::{
11    routing::{delete, get, patch, post, put},
12    Router as AxumRouter,
13};
14use elif_core::container::IocContainer;
15use std::collections::HashMap;
16use std::future::Future;
17use std::pin::Pin;
18use std::sync::{Arc, Mutex};
19
20/// Main router for the elif.rs framework
21#[derive(Debug)]
22pub struct Router<S = ()>
23where
24    S: Clone + Send + Sync + 'static,
25{
26    axum_router: AxumRouter<S>,
27    registry: Arc<Mutex<RouteRegistry>>,
28    route_counter: Arc<Mutex<usize>>,
29    middleware_stack: MiddlewarePipelineV2,
30    middleware_groups: HashMap<String, MiddlewarePipelineV2>,
31    route_middleware: HashMap<String, Vec<String>>, // route_id -> middleware group names
32    controller_registry: Arc<Mutex<ControllerRegistry>>,
33    ioc_container: Option<Arc<IocContainer>>,
34}
35
36impl<S> Router<S>
37where
38    S: Clone + Send + Sync + 'static,
39{
40    /// Create a new router
41    pub fn new() -> Self {
42        Self {
43            axum_router: AxumRouter::new(),
44            registry: Arc::new(Mutex::new(RouteRegistry::new())),
45            route_counter: Arc::new(Mutex::new(0)),
46            middleware_stack: MiddlewarePipelineV2::new(),
47            middleware_groups: HashMap::new(),
48            route_middleware: HashMap::new(),
49            controller_registry: Arc::new(Mutex::new(ControllerRegistry::new())),
50            ioc_container: None,
51        }
52    }
53
54    /// Create a new router with state
55    pub fn with_state(state: S) -> Self {
56        Self {
57            axum_router: AxumRouter::new().with_state(state),
58            registry: Arc::new(Mutex::new(RouteRegistry::new())),
59            route_counter: Arc::new(Mutex::new(0)),
60            middleware_stack: MiddlewarePipelineV2::new(),
61            middleware_groups: HashMap::new(),
62            route_middleware: HashMap::new(),
63            controller_registry: Arc::new(Mutex::new(ControllerRegistry::new())),
64            ioc_container: None,
65        }
66    }
67
68    /// Generate a unique route ID
69    fn next_route_id(&self) -> String {
70        let mut counter = self.route_counter.lock().unwrap();
71        *counter += 1;
72        format!("route_{}", counter)
73    }
74
75    /// Register a route with the registry
76    fn register_route(&self, method: HttpMethod, path: &str, name: Option<String>) -> String {
77        let route_id = self.next_route_id();
78        let params = self.extract_param_names(path);
79
80        let route_info = RouteInfo {
81            name: name.clone(),
82            path: path.to_string(),
83            method,
84            params,
85            group: None, // TODO: Support groups
86        };
87
88        self.registry
89            .lock()
90            .unwrap()
91            .register(route_id.clone(), route_info);
92        route_id
93    }
94
95    /// Extract parameter names from a route path
96    fn extract_param_names(&self, path: &str) -> Vec<String> {
97        path.split('/')
98            .filter_map(|segment| {
99                if segment.starts_with('{') && segment.ends_with('}') {
100                    Some(segment[1..segment.len() - 1].to_string())
101                } else {
102                    None
103                }
104            })
105            .collect()
106    }
107
108    /// Add global middleware to the router
109    pub fn use_middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
110        self.middleware_stack = self.middleware_stack.add(middleware);
111        self
112    }
113
114    /// Extend router middleware with external middleware pipeline
115    /// External middleware will be executed before the router's own middleware
116    pub fn extend_middleware(mut self, external_middleware: MiddlewarePipelineV2) -> Self {
117        self.middleware_stack = external_middleware.extend(self.middleware_stack);
118        self
119    }
120
121    /// Create a named middleware group for use with route-specific middleware
122    pub fn middleware_group(mut self, name: &str, middleware: Vec<Arc<dyn Middleware>>) -> Self {
123        let pipeline = MiddlewarePipelineV2::from(middleware);
124        self.middleware_groups.insert(name.to_string(), pipeline);
125        self
126    }
127
128    /// Create a route builder for defining routes with middleware groups
129    pub fn route(self, path: &str) -> RouteBuilder<S> {
130        RouteBuilder::new(self, path.to_string())
131    }
132
133    /// Private helper method to add routes with less duplication
134    fn add_route<F, Fut, R, M>(
135        mut self,
136        method: HttpMethod,
137        path: &str,
138        handler: F,
139        method_router_fn: M,
140    ) -> Self
141    where
142        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
143        Fut: Future<Output = HttpResult<R>> + Send + 'static,
144        R: IntoElifResponse + Send + 'static,
145        M: FnOnce(
146            crate::handlers::handler::ElifHandlerWrapper<F, Fut, R>,
147        ) -> axum::routing::MethodRouter<S>,
148    {
149        self.register_route(method, path, None);
150        let method_router = method_router_fn(elif_handler(handler));
151        self.axum_router = self.axum_router.route(path, method_router);
152        self
153    }
154
155    /// Add a GET route with elif handler
156    pub fn get<F, Fut, R>(self, path: &str, handler: F) -> Self
157    where
158        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
159        Fut: Future<Output = HttpResult<R>> + Send + 'static,
160        R: IntoElifResponse + Send + 'static,
161    {
162        self.add_route(HttpMethod::GET, path, handler, get)
163    }
164
165    /// Add a POST route with elif handler
166    pub fn post<F, Fut, R>(self, path: &str, handler: F) -> Self
167    where
168        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
169        Fut: Future<Output = HttpResult<R>> + Send + 'static,
170        R: IntoElifResponse + Send + 'static,
171    {
172        self.add_route(HttpMethod::POST, path, handler, post)
173    }
174
175    /// Add a PUT route with elif handler
176    pub fn put<F, Fut, R>(self, path: &str, handler: F) -> Self
177    where
178        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
179        Fut: Future<Output = HttpResult<R>> + Send + 'static,
180        R: IntoElifResponse + Send + 'static,
181    {
182        self.add_route(HttpMethod::PUT, path, handler, put)
183    }
184
185    /// Add a DELETE route with elif handler
186    pub fn delete<F, Fut, R>(self, path: &str, handler: F) -> Self
187    where
188        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
189        Fut: Future<Output = HttpResult<R>> + Send + 'static,
190        R: IntoElifResponse + Send + 'static,
191    {
192        self.add_route(HttpMethod::DELETE, path, handler, delete)
193    }
194
195    /// Add a PATCH route with elif handler
196    pub fn patch<F, Fut, R>(self, path: &str, handler: F) -> Self
197    where
198        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
199        Fut: Future<Output = HttpResult<R>> + Send + 'static,
200        R: IntoElifResponse + Send + 'static,
201    {
202        self.add_route(HttpMethod::PATCH, path, handler, patch)
203    }
204
205    /// Register a controller with automatic route registration
206    pub fn controller<C>(mut self, controller: C) -> Self
207    where
208        C: ElifController + 'static,
209    {
210        let base_path = controller.base_path().to_string();
211        let controller_name = controller.name().to_string();
212        let controller_arc = Arc::new(controller);
213
214        // Register all controller routes
215        for route in controller_arc.routes() {
216            let full_path = self.combine_paths(&base_path, &route.path);
217            let handler =
218                controller_handler(Arc::clone(&controller_arc), route.handler_name.clone());
219
220            self = match route.method {
221                HttpMethod::GET => self.get(&full_path, handler),
222                HttpMethod::POST => self.post(&full_path, handler),
223                HttpMethod::PUT => self.put(&full_path, handler),
224                HttpMethod::DELETE => self.delete(&full_path, handler),
225                HttpMethod::PATCH => self.patch(&full_path, handler),
226                _ => {
227                    // For unsupported HTTP methods, we'll skip for now
228                    // This can be extended to support more methods
229                    continue;
230                }
231            };
232
233            // TODO: Apply route-specific middleware
234            // This will be implemented when middleware system is enhanced
235        }
236
237        // Store controller reference for introspection
238        if let Ok(mut registry) = self.controller_registry.lock() {
239            registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
240        }
241
242        self
243    }
244
245    /// Set the IoC container for controller dependency injection
246    pub fn with_ioc_container(mut self, container: Arc<IocContainer>) -> Self {
247        self.ioc_container = Some(container);
248        self
249    }
250
251    /// Register a controller type that will be resolved from the IoC container
252    /// The controller type must implement both ElifController and IocControllable
253    pub fn controller_from_container<C>(self) -> Self
254    where
255        C: ElifController + IocControllable + 'static,
256    {
257        let container = self.ioc_container.as_ref()
258            .expect("IoC container must be set before registering IoC controllers. Use .with_ioc_container() first");
259
260        // Resolve the singleton controller instance once during startup
261        let controller_arc = match C::from_ioc_container(container, None) {
262            Ok(controller) => Arc::new(controller),
263            Err(err) => {
264                eprintln!(
265                    "Warning: Failed to create singleton controller instance: {}",
266                    err
267                );
268                return self;
269            }
270        };
271
272        let base_path = controller_arc.base_path().to_string();
273        let controller_name = controller_arc.name().to_string();
274
275        // Register all controller routes with the single controller instance
276        let mut router = self;
277        for route in controller_arc.routes() {
278            let full_path = router.combine_paths(&base_path, &route.path);
279            let handler_controller_arc = Arc::clone(&controller_arc);
280            let method_name = route.handler_name.clone();
281
282            let handler = move |request: ElifRequest| {
283                let controller = Arc::clone(&handler_controller_arc);
284                let method_name = method_name.clone();
285                Box::pin(async move { controller.handle_request(method_name, request).await })
286            };
287
288            router = match route.method {
289                HttpMethod::GET => router.get(&full_path, handler),
290                HttpMethod::POST => router.post(&full_path, handler),
291                HttpMethod::PUT => router.put(&full_path, handler),
292                HttpMethod::DELETE => router.delete(&full_path, handler),
293                HttpMethod::PATCH => router.patch(&full_path, handler),
294                _ => {
295                    // For unsupported HTTP methods, we'll skip for now
296                    continue;
297                }
298            };
299
300            // TODO: Apply route-specific middleware
301        }
302
303        // Store the actual controller instance for introspection
304        if let Ok(mut registry) = router.controller_registry.lock() {
305            registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
306        }
307
308        router
309    }
310
311    /// Register a controller type with request-scoped dependency injection
312    /// This creates controllers per request with scoped dependencies
313    pub fn scoped_controller_from_container<C>(self) -> Self
314    where
315        C: ElifController + IocControllable + 'static,
316    {
317        let container = self.ioc_container.as_ref()
318            .expect("IoC container must be set before registering IoC controllers. Use .with_ioc_container() first");
319        let container_arc = Arc::clone(container);
320
321        // Create a temporary controller instance to get its metadata
322        let temp_controller = match C::from_ioc_container(container, None) {
323            Ok(controller) => controller,
324            Err(err) => {
325                eprintln!(
326                    "Warning: Failed to create controller for route registration: {}",
327                    err
328                );
329                return self;
330            }
331        };
332
333        let base_path = temp_controller.base_path().to_string();
334        let controller_name = temp_controller.name().to_string();
335
336        // Register all controller routes with scoped IoC-resolved handlers
337        let mut router = self;
338        for route in temp_controller.routes() {
339            let full_path = router.combine_paths(&base_path, &route.path);
340            let handler = scoped_ioc_controller_handler::<C>(
341                Arc::clone(&container_arc),
342                route.handler_name.clone(),
343            );
344
345            router = match route.method {
346                HttpMethod::GET => router.get(&full_path, handler),
347                HttpMethod::POST => router.post(&full_path, handler),
348                HttpMethod::PUT => router.put(&full_path, handler),
349                HttpMethod::DELETE => router.delete(&full_path, handler),
350                HttpMethod::PATCH => router.patch(&full_path, handler),
351                _ => {
352                    continue;
353                }
354            };
355        }
356
357        // Store controller type info
358        if let Ok(mut registry) = router.controller_registry.lock() {
359            let controller_arc = Arc::new(temp_controller);
360            registry.register(controller_name, controller_arc as Arc<dyn ElifController>);
361        }
362
363        router
364    }
365
366    /// Helper method to combine base path and route path
367    fn combine_paths(&self, base: &str, route: &str) -> String {
368        let base = base.trim_end_matches('/');
369        let route = route.trim_start_matches('/');
370
371        let path = if route.is_empty() {
372            base.to_string()
373        } else if base.is_empty() {
374            format!("/{}", route)
375        } else {
376            format!("{}/{}", base, route)
377        };
378
379        // Ensure path is never empty to prevent Axum panics
380        if path.is_empty() {
381            "/".to_string()
382        } else {
383            path
384        }
385    }
386
387    /// Merge another ElifRouter - the primary method for composing routers
388    pub fn merge(mut self, other: Router<S>) -> Self {
389        // Merge the registries with unique IDs to avoid conflicts
390        if let (Ok(mut self_registry), Ok(other_registry)) =
391            (self.registry.lock(), other.registry.lock())
392        {
393            for route_info in other_registry.all_routes().values() {
394                // Generate a new unique ID for the merged route to avoid ID conflicts
395                let new_id = self.next_route_id();
396                self_registry.register(new_id, route_info.clone());
397            }
398        }
399
400        // Merge middleware groups and route-specific middleware mappings
401        self.middleware_groups.extend(other.middleware_groups);
402        self.route_middleware.extend(other.route_middleware);
403
404        // Merge controller registries - avoid deadlock by not holding both locks simultaneously
405        if let Ok(other_controller_registry) = other.controller_registry.lock() {
406            let controllers_to_merge: Vec<_> = other_controller_registry
407                .all_controllers()
408                .map(|(name, controller)| (name.clone(), Arc::clone(controller)))
409                .collect();
410
411            // Release the other lock before acquiring self lock
412            drop(other_controller_registry);
413
414            if let Ok(mut self_controller_registry) = self.controller_registry.lock() {
415                for (name, controller) in controllers_to_merge {
416                    self_controller_registry.register(name, controller);
417                }
418            }
419        }
420
421        // Merge IoC containers (prefer self's container if both exist)
422        if self.ioc_container.is_none() && other.ioc_container.is_some() {
423            self.ioc_container = other.ioc_container;
424        }
425
426        // Merge global middleware stacks. The middleware from `self` will run first.
427        self.middleware_stack = self.middleware_stack.extend(other.middleware_stack);
428
429        // Merge the underlying Axum routers
430        self.axum_router = self.axum_router.merge(other.axum_router);
431        self
432    }
433
434    /// Internal method to merge with Axum router (for framework internals only)
435    pub(crate) fn merge_axum(mut self, other: AxumRouter<S>) -> Self {
436        self.axum_router = self.axum_router.merge(other);
437        self
438    }
439
440    /// Nest routes under a path prefix
441    ///
442    /// The nested router's global middleware will be applied only to the nested routes,
443    /// not to the parent router's routes. This is achieved by converting the nested
444    /// router's middleware pipeline into an Axum Layer before nesting.
445    pub fn nest(mut self, path: &str, router: Router<S>) -> Self {
446        // Note: Nested routes inherit their path prefix, so we don't need to modify the registry paths
447        // The registry will contain the original paths, and Axum handles the prefixing internally
448        // Merge nested router's routes into parent registry with unique IDs
449        if let (Ok(mut self_registry), Ok(router_registry)) =
450            (self.registry.lock(), router.registry.lock())
451        {
452            for route_info in router_registry.all_routes().values() {
453                // Generate a new unique ID for the nested route to avoid ID conflicts
454                let new_id = self.next_route_id();
455                self_registry.register(new_id, route_info.clone());
456            }
457        }
458
459        // Merge middleware groups and route-specific middleware mappings from nested router
460        self.middleware_groups.extend(router.middleware_groups);
461        self.route_middleware.extend(router.route_middleware);
462
463        // Apply nested router's global middleware as a layer before nesting
464        // This ensures the middleware only applies to the nested routes
465        let has_nested_middleware = !router.middleware_stack.is_empty();
466        let nested_middleware = router.middleware_stack.clone();
467        let nested_axum_router = router.axum_router;
468
469        let nested_axum_router = if has_nested_middleware {
470            use axum::extract::Request;
471            use axum::middleware::from_fn;
472            use axum::middleware::Next;
473
474            // Create a layer from the nested router's middleware pipeline
475            nested_axum_router.layer(from_fn(move |req: Request, next: Next| {
476                let pipeline = nested_middleware.clone();
477                async move {
478                    // Convert axum request to ElifRequest
479                    let elif_req = crate::request::ElifRequest::from_axum_request(req).await;
480
481                    // Execute middleware pipeline
482                    let response = pipeline
483                        .execute(elif_req, |req| {
484                            Box::pin(async move {
485                                // Convert back to axum request for next handler
486                                let axum_req = req.into_axum_request();
487                                let axum_response = next.run(axum_req).await;
488                                // Convert axum response to ElifResponse
489                                crate::response::ElifResponse::from_axum_response(axum_response)
490                                    .await
491                            })
492                        })
493                        .await;
494
495                    // Convert ElifResponse back to axum response
496                    response.into_axum_response()
497                }
498            }))
499        } else {
500            nested_axum_router
501        };
502
503        self.axum_router = self.axum_router.nest(path, nested_axum_router);
504        self
505    }
506
507    /// Get the underlying Axum router
508    pub fn into_axum_router(self) -> AxumRouter<S> {
509        self.axum_router
510    }
511
512    /// Get route registry for introspection
513    pub fn registry(&self) -> Arc<Mutex<RouteRegistry>> {
514        Arc::clone(&self.registry)
515    }
516
517    /// Generate URL for a named route
518    pub fn url_for(&self, name: &str, params: &HashMap<String, String>) -> Option<String> {
519        let registry = self.registry.lock().unwrap();
520        if let Some(route) = registry.get_by_name(name) {
521            let mut url = route.path.clone();
522            for (key, value) in params {
523                url = url.replace(&format!("{{{}}}", key), value);
524            }
525            Some(url)
526        } else {
527            None
528        }
529    }
530
531    /// Get the global middleware pipeline
532    pub fn middleware_pipeline(&self) -> &MiddlewarePipelineV2 {
533        &self.middleware_stack
534    }
535
536    /// Get available middleware groups
537    pub fn middleware_groups(&self) -> &HashMap<String, MiddlewarePipelineV2> {
538        &self.middleware_groups
539    }
540
541    /// Get route-specific middleware mappings
542    pub fn route_middleware(&self) -> &HashMap<String, Vec<String>> {
543        &self.route_middleware
544    }
545
546    /// Get the controller registry for introspection
547    pub fn controller_registry(&self) -> Arc<Mutex<ControllerRegistry>> {
548        Arc::clone(&self.controller_registry)
549    }
550
551    /// Get the IoC container if set
552    pub fn ioc_container(&self) -> Option<&Arc<IocContainer>> {
553        self.ioc_container.as_ref()
554    }
555
556    /// Add a raw Axum route while preserving router state (for internal use)
557    pub(crate) fn add_axum_route(
558        mut self,
559        path: &str,
560        method_router: axum::routing::MethodRouter<S>,
561    ) -> Self {
562        self.axum_router = self.axum_router.route(path, method_router);
563        self
564    }
565}
566
567impl<S> Default for Router<S>
568where
569    S: Clone + Send + Sync + 'static,
570{
571    fn default() -> Self {
572        Self::new()
573    }
574}
575
576/// Builder for creating routes with middleware groups and additional metadata
577pub struct RouteBuilder<S = ()>
578where
579    S: Clone + Send + Sync + 'static,
580{
581    router: Router<S>,
582    path: String,
583    middleware_groups: Vec<String>,
584    name: Option<String>,
585}
586
587impl<S> RouteBuilder<S>
588where
589    S: Clone + Send + Sync + 'static,
590{
591    pub fn new(router: Router<S>, path: String) -> Self {
592        Self {
593            router,
594            path,
595            middleware_groups: Vec::new(),
596            name: None,
597        }
598    }
599
600    /// Apply a middleware group to this route
601    pub fn use_group(mut self, group_name: &str) -> Self {
602        self.middleware_groups.push(group_name.to_string());
603        self
604    }
605
606    /// Set route name for URL generation
607    pub fn name(mut self, name: &str) -> Self {
608        self.name = Some(name.to_string());
609        self
610    }
611
612    /// Private helper method for RouteBuilder route registration
613    fn add_method_route<F, Fut, R, M>(
614        mut self,
615        method: HttpMethod,
616        handler: F,
617        method_router_fn: M,
618    ) -> Router<S>
619    where
620        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
621        Fut: Future<Output = HttpResult<R>> + Send + 'static,
622        R: IntoElifResponse + Send + 'static,
623        M: FnOnce(
624            crate::handlers::handler::ElifHandlerWrapper<F, Fut, R>,
625        ) -> axum::routing::MethodRouter<S>,
626    {
627        let route_id = self
628            .router
629            .register_route(method, &self.path, self.name.clone());
630        self.router
631            .route_middleware
632            .insert(route_id, self.middleware_groups);
633        let method_router = method_router_fn(elif_handler(handler));
634        self.router.axum_router = self.router.axum_router.route(&self.path, method_router);
635        self.router
636    }
637
638    /// Add a GET route with elif handler
639    pub fn get<F, Fut, R>(self, handler: F) -> Router<S>
640    where
641        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
642        Fut: Future<Output = HttpResult<R>> + Send + 'static,
643        R: IntoElifResponse + Send + 'static,
644    {
645        self.add_method_route(HttpMethod::GET, handler, get)
646    }
647
648    /// Add a POST route with elif handler
649    pub fn post<F, Fut, R>(self, handler: F) -> Router<S>
650    where
651        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
652        Fut: Future<Output = HttpResult<R>> + Send + 'static,
653        R: IntoElifResponse + Send + 'static,
654    {
655        self.add_method_route(HttpMethod::POST, handler, post)
656    }
657
658    /// Add a PUT route with elif handler
659    pub fn put<F, Fut, R>(self, handler: F) -> Router<S>
660    where
661        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
662        Fut: Future<Output = HttpResult<R>> + Send + 'static,
663        R: IntoElifResponse + Send + 'static,
664    {
665        self.add_method_route(HttpMethod::PUT, handler, put)
666    }
667
668    /// Add a DELETE route with elif handler
669    pub fn delete<F, Fut, R>(self, handler: F) -> Router<S>
670    where
671        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
672        Fut: Future<Output = HttpResult<R>> + Send + 'static,
673        R: IntoElifResponse + Send + 'static,
674    {
675        self.add_method_route(HttpMethod::DELETE, handler, delete)
676    }
677
678    /// Add a PATCH route with elif handler
679    pub fn patch<F, Fut, R>(self, handler: F) -> Router<S>
680    where
681        F: Fn(ElifRequest) -> Fut + Send + Clone + 'static,
682        Fut: Future<Output = HttpResult<R>> + Send + 'static,
683        R: IntoElifResponse + Send + 'static,
684    {
685        self.add_method_route(HttpMethod::PATCH, handler, patch)
686    }
687}
688
689#[cfg(test)]
690mod tests {
691    use super::*;
692    use crate::errors::HttpResult;
693    use crate::request::ElifRequest;
694    use crate::response::ElifResponse;
695
696    async fn elif_handler(_req: ElifRequest) -> HttpResult<ElifResponse> {
697        Ok(ElifResponse::ok().text("Hello, World!"))
698    }
699
700    #[test]
701    fn test_router_creation() {
702        let router = Router::<()>::new()
703            .get("/", elif_handler)
704            .post("/users", elif_handler)
705            .get("/users/{id}", elif_handler);
706
707        let registry = router.registry();
708        let reg = registry.lock().unwrap();
709        assert_eq!(reg.all_routes().len(), 3);
710    }
711
712    #[test]
713    fn test_param_extraction() {
714        let router = Router::<()>::new();
715        let params = router.extract_param_names("/users/{id}/posts/{slug}");
716        assert_eq!(params, vec!["id", "slug"]);
717    }
718
719    #[test]
720    fn test_url_generation() {
721        let router = Router::<()>::new().get("/users/{id}/posts/{slug}", elif_handler);
722
723        // Manually add a named route to registry for testing
724        {
725            let mut registry = router.registry.lock().unwrap();
726            let route_info = RouteInfo {
727                name: Some("user.posts.show".to_string()),
728                path: "/users/{id}/posts/{slug}".to_string(),
729                method: HttpMethod::GET,
730                params: vec!["id".to_string(), "slug".to_string()],
731                group: None,
732            };
733            registry.register("test_route".to_string(), route_info);
734        }
735
736        let mut params = HashMap::new();
737        params.insert("id".to_string(), "123".to_string());
738        params.insert("slug".to_string(), "hello-world".to_string());
739
740        let url = router.url_for("user.posts.show", &params);
741        assert_eq!(url, Some("/users/123/posts/hello-world".to_string()));
742    }
743
744    #[test]
745    fn test_middleware_integration() {
746        use crate::middleware::v2::LoggingMiddleware;
747
748        let router = Router::<()>::new()
749            .use_middleware(LoggingMiddleware)
750            .get("/", elif_handler);
751
752        // Verify middleware was added to the pipeline
753        assert_eq!(router.middleware_pipeline().len(), 1);
754        assert_eq!(
755            router.middleware_pipeline().names(),
756            vec!["LoggingMiddleware"]
757        );
758    }
759
760    #[test]
761    fn test_middleware_groups() {
762        use crate::middleware::v2::LoggingMiddleware;
763        use std::sync::Arc;
764
765        let router = Router::<()>::new()
766            .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
767            .get("/", elif_handler);
768
769        // Verify middleware group was created
770        assert!(router.middleware_groups().contains_key("api"));
771
772        // Verify the middleware group contains the actual middleware
773        let api_group = router.middleware_groups().get("api").unwrap();
774        assert_eq!(api_group.len(), 1);
775        assert_eq!(api_group.names(), vec!["LoggingMiddleware"]);
776    }
777
778    #[test]
779    fn test_router_merge_with_middleware() {
780        use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
781        use std::sync::Arc;
782
783        let router1 = Router::<()>::new()
784            .use_middleware(LoggingMiddleware)
785            .middleware_group(
786                "auth",
787                vec![Arc::new(SimpleAuthMiddleware::new("secret".to_string()))],
788            );
789
790        let router2 = Router::<()>::new()
791            .use_middleware(SimpleAuthMiddleware::new("token".to_string()))
792            .middleware_group("api", vec![Arc::new(LoggingMiddleware)]);
793
794        let merged = router1.merge(router2);
795
796        // Verify that middleware groups were merged
797        assert!(merged.middleware_groups().contains_key("auth"));
798        assert!(merged.middleware_groups().contains_key("api"));
799
800        // Verify middleware groups contain the correct middleware
801        let auth_group = merged.middleware_groups().get("auth").unwrap();
802        assert_eq!(auth_group.len(), 1);
803        assert_eq!(auth_group.names(), vec!["SimpleAuthMiddleware"]);
804
805        let api_group = merged.middleware_groups().get("api").unwrap();
806        assert_eq!(api_group.len(), 1);
807        assert_eq!(api_group.names(), vec!["LoggingMiddleware"]);
808
809        // Verify global middleware from both routers is preserved and merged
810        assert_eq!(merged.middleware_pipeline().len(), 2);
811        assert_eq!(
812            merged.middleware_pipeline().names(),
813            vec!["LoggingMiddleware", "SimpleAuthMiddleware"]
814        );
815    }
816
817    #[test]
818    fn test_middleware_group_with_multiple_middleware() {
819        use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
820        use std::sync::Arc;
821
822        let router = Router::<()>::new()
823            .middleware_group(
824                "api",
825                vec![
826                    Arc::new(LoggingMiddleware),
827                    Arc::new(SimpleAuthMiddleware::new("secret".to_string())),
828                ],
829            )
830            .get("/", elif_handler);
831
832        // Verify middleware group contains both middleware
833        let api_group = router.middleware_groups().get("api").unwrap();
834        assert_eq!(api_group.len(), 2);
835        assert_eq!(
836            api_group.names(),
837            vec!["LoggingMiddleware", "SimpleAuthMiddleware"]
838        );
839    }
840
841    #[test]
842    fn test_middleware_merge_preserves_global_middleware() {
843        use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
844
845        // Test that global middleware from both routers is preserved during merge
846        let router1 = Router::<()>::new()
847            .use_middleware(LoggingMiddleware)
848            .use_middleware(SimpleAuthMiddleware::new("router1".to_string()));
849
850        let router2 = Router::<()>::new()
851            .use_middleware(SimpleAuthMiddleware::new("router2".to_string()))
852            .use_middleware(LoggingMiddleware);
853
854        let merged = router1.merge(router2);
855
856        // Should have all 4 middleware instances: 2 from router1 + 2 from router2
857        assert_eq!(merged.middleware_pipeline().len(), 4);
858
859        // Verify execution order: router1's middleware first, then router2's
860        assert_eq!(
861            merged.middleware_pipeline().names(),
862            vec![
863                "LoggingMiddleware",
864                "SimpleAuthMiddleware",
865                "SimpleAuthMiddleware",
866                "LoggingMiddleware"
867            ]
868        );
869    }
870
871    #[test]
872    fn test_nested_router_middleware_scoping() {
873        use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
874
875        // Create parent router with its own middleware
876        let parent_router = Router::<()>::new()
877            .use_middleware(LoggingMiddleware)
878            .get("/parent", elif_handler);
879
880        // Create nested router with different middleware
881        let nested_router = Router::<()>::new()
882            .use_middleware(SimpleAuthMiddleware::new("nested_secret".to_string()))
883            .get("/nested", elif_handler);
884
885        // Nest the router
886        let composed_router = parent_router.nest("/api", nested_router);
887
888        // Verify parent router's middleware is preserved
889        assert_eq!(composed_router.middleware_pipeline().len(), 1);
890        assert_eq!(
891            composed_router.middleware_pipeline().names(),
892            vec!["LoggingMiddleware"]
893        );
894
895        // Verify route registry contains both routes from both routers
896        // The nested router's routes should be merged into the parent registry
897        let registry = composed_router.registry();
898        let reg = registry.lock().unwrap();
899        let route_count = reg.all_routes().len();
900
901        // Should have both parent route (/parent) and nested route (/nested)
902        // Note: If this fails, the issue is likely in the nest() registry merging logic
903        assert_eq!(
904            route_count, 2,
905            "Expected 2 routes after nesting (parent + nested)"
906        );
907
908        // The nested router's middleware should be applied as a layer to the nested routes
909        // This test verifies the structure is correct - actual middleware execution
910        // would need integration tests with a running server
911    }
912
913    #[test]
914    fn test_nested_router_middleware_groups_merged() {
915        use crate::middleware::v2::LoggingMiddleware;
916        use std::sync::Arc;
917
918        // Create parent router with middleware group
919        let parent_router = Router::<()>::new()
920            .middleware_group("parent_group", vec![Arc::new(LoggingMiddleware)])
921            .get("/parent", elif_handler);
922
923        // Create nested router with different middleware group
924        let nested_router = Router::<()>::new()
925            .middleware_group("nested_group", vec![Arc::new(LoggingMiddleware)])
926            .get("/nested", elif_handler);
927
928        // Nest the router
929        let composed_router = parent_router.nest("/api", nested_router);
930
931        // Verify both middleware groups are preserved
932        assert!(composed_router
933            .middleware_groups()
934            .contains_key("parent_group"));
935        assert!(composed_router
936            .middleware_groups()
937            .contains_key("nested_group"));
938
939        // Verify the groups contain the correct middleware
940        let parent_group = composed_router
941            .middleware_groups()
942            .get("parent_group")
943            .unwrap();
944        assert_eq!(parent_group.len(), 1);
945        assert_eq!(parent_group.names(), vec!["LoggingMiddleware"]);
946
947        let nested_group = composed_router
948            .middleware_groups()
949            .get("nested_group")
950            .unwrap();
951        assert_eq!(nested_group.len(), 1);
952        assert_eq!(nested_group.names(), vec!["LoggingMiddleware"]);
953    }
954
955    #[test]
956    fn test_nested_router_empty_middleware_optimization() {
957        use crate::middleware::v2::LoggingMiddleware;
958
959        // Create parent router with middleware
960        let parent_router = Router::<()>::new()
961            .use_middleware(LoggingMiddleware)
962            .get("/parent", elif_handler);
963
964        // Create nested router WITHOUT middleware (empty pipeline)
965        let nested_router = Router::<()>::new().get("/nested", elif_handler);
966
967        // Verify nested router has empty middleware
968        assert_eq!(nested_router.middleware_pipeline().len(), 0);
969        assert!(nested_router.middleware_pipeline().is_empty());
970
971        // Nest the router
972        let composed_router = parent_router.nest("/api", nested_router);
973
974        // Parent middleware should still be there
975        assert_eq!(composed_router.middleware_pipeline().len(), 1);
976        assert_eq!(
977            composed_router.middleware_pipeline().names(),
978            vec!["LoggingMiddleware"]
979        );
980
981        // The implementation should optimize for empty nested middleware
982        // (no unnecessary layer application)
983    }
984
985    #[test]
986    fn test_controller_registration() {
987        use crate::controller::{ControllerRoute, ElifController, RouteParam};
988        use crate::routing::params::ParamType;
989
990        // Create a test controller
991        struct TestController;
992
993        #[async_trait::async_trait]
994        impl ElifController for TestController {
995            fn name(&self) -> &str {
996                "TestController"
997            }
998            fn base_path(&self) -> &str {
999                "/test"
1000            }
1001
1002            fn routes(&self) -> Vec<ControllerRoute> {
1003                vec![
1004                    ControllerRoute::new(HttpMethod::GET, "", "list"),
1005                    ControllerRoute::new(HttpMethod::GET, "/{id}", "show")
1006                        .add_param(RouteParam::new("id", ParamType::Integer)),
1007                    ControllerRoute::new(HttpMethod::POST, "", "create"),
1008                ]
1009            }
1010
1011            async fn handle_request(
1012                self: std::sync::Arc<Self>,
1013                method_name: String,
1014                _request: ElifRequest,
1015            ) -> HttpResult<ElifResponse> {
1016                match method_name.as_str() {
1017                    "list" => Ok(ElifResponse::ok().text("List method")),
1018                    "show" => Ok(ElifResponse::ok().text("Show method")),
1019                    "create" => Ok(ElifResponse::ok().text("Create method")),
1020                    _ => Ok(ElifResponse::not_found().text("Method not found")),
1021                }
1022            }
1023        }
1024
1025        let controller = TestController;
1026        let router = Router::<()>::new().controller(controller);
1027
1028        // Check that routes were registered
1029        let registry = router.registry();
1030        let reg = registry.lock().unwrap();
1031        assert_eq!(reg.all_routes().len(), 3);
1032
1033        // Check that controller was registered
1034        let controller_registry = router.controller_registry();
1035        let ctrl_reg = controller_registry.lock().unwrap();
1036        assert!(ctrl_reg.get_controller("TestController").is_some());
1037    }
1038
1039    #[test]
1040    fn test_combine_paths_edge_cases() {
1041        let router = Router::<()>::new();
1042
1043        // Test normal cases
1044        assert_eq!(router.combine_paths("/users", "/posts"), "/users/posts");
1045        assert_eq!(router.combine_paths("/users", "posts"), "/users/posts");
1046        assert_eq!(router.combine_paths("users", "/posts"), "users/posts");
1047        assert_eq!(router.combine_paths("users", "posts"), "users/posts");
1048
1049        // Test edge cases that could produce empty paths
1050        assert_eq!(router.combine_paths("", ""), "/"); // Both empty -> root
1051        assert_eq!(router.combine_paths("/", ""), "/"); // Base is root, route empty
1052        assert_eq!(router.combine_paths("", "/"), "/"); // Base empty, route is root
1053        assert_eq!(router.combine_paths("/", "/"), "/"); // Both are root
1054
1055        // Test with trailing/leading slashes
1056        assert_eq!(router.combine_paths("/users/", ""), "/users");
1057        assert_eq!(router.combine_paths("/users/", "/posts"), "/users/posts");
1058        assert_eq!(router.combine_paths("/", "posts"), "/posts");
1059        assert_eq!(router.combine_paths("users", "/"), "users");
1060    }
1061
1062    #[test]
1063    fn test_controller_with_root_base_path() {
1064        use crate::controller::{ControllerRoute, ElifController};
1065
1066        // Create a controller with root base path
1067        struct RootController;
1068
1069        #[async_trait::async_trait]
1070        impl ElifController for RootController {
1071            fn name(&self) -> &str {
1072                "RootController"
1073            }
1074            fn base_path(&self) -> &str {
1075                "/"
1076            } // Root base path
1077
1078            fn routes(&self) -> Vec<ControllerRoute> {
1079                vec![
1080                    ControllerRoute::new(HttpMethod::GET, "", "home"), // Should become "/"
1081                    ControllerRoute::new(HttpMethod::GET, "/health", "health"), // Should become "/health"
1082                ]
1083            }
1084
1085            async fn handle_request(
1086                self: std::sync::Arc<Self>,
1087                method_name: String,
1088                _request: ElifRequest,
1089            ) -> HttpResult<ElifResponse> {
1090                match method_name.as_str() {
1091                    "home" => Ok(ElifResponse::ok().text("Home")),
1092                    "health" => Ok(ElifResponse::ok().text("Health")),
1093                    _ => Ok(ElifResponse::not_found().text("Not found")),
1094                }
1095            }
1096        }
1097
1098        let controller = RootController;
1099        let router = Router::<()>::new().controller(controller);
1100
1101        // Check that routes were registered correctly
1102        let registry = router.registry();
1103        let reg = registry.lock().unwrap();
1104        let routes = reg.all_routes();
1105
1106        // Should have 2 routes
1107        assert_eq!(routes.len(), 2);
1108
1109        // Verify paths are correct (one should be "/" and one should be "/health")
1110        let paths: Vec<&String> = routes.values().map(|route| &route.path).collect();
1111        assert!(paths.contains(&&"/".to_string()));
1112        assert!(paths.contains(&&"/health".to_string()));
1113    }
1114
1115    #[test]
1116    fn test_controller_with_empty_base_path() {
1117        use crate::controller::{ControllerRoute, ElifController};
1118
1119        // Create a controller with empty base path
1120        struct EmptyBaseController;
1121
1122        #[async_trait::async_trait]
1123        impl ElifController for EmptyBaseController {
1124            fn name(&self) -> &str {
1125                "EmptyBaseController"
1126            }
1127            fn base_path(&self) -> &str {
1128                ""
1129            } // Empty base path
1130
1131            fn routes(&self) -> Vec<ControllerRoute> {
1132                vec![
1133                    ControllerRoute::new(HttpMethod::GET, "", "root"), // Should become "/"
1134                    ControllerRoute::new(HttpMethod::GET, "/api", "api"), // Should become "/api"
1135                ]
1136            }
1137
1138            async fn handle_request(
1139                self: std::sync::Arc<Self>,
1140                method_name: String,
1141                _request: ElifRequest,
1142            ) -> HttpResult<ElifResponse> {
1143                match method_name.as_str() {
1144                    "root" => Ok(ElifResponse::ok().text("Root")),
1145                    "api" => Ok(ElifResponse::ok().text("API")),
1146                    _ => Ok(ElifResponse::not_found().text("Not found")),
1147                }
1148            }
1149        }
1150
1151        let controller = EmptyBaseController;
1152        let router = Router::<()>::new().controller(controller);
1153
1154        // Check that routes were registered correctly
1155        let registry = router.registry();
1156        let reg = registry.lock().unwrap();
1157        let routes = reg.all_routes();
1158
1159        // Should have 2 routes
1160        assert_eq!(routes.len(), 2);
1161
1162        // Verify paths are correct
1163        let paths: Vec<&String> = routes.values().map(|route| &route.path).collect();
1164        assert!(paths.contains(&&"/".to_string()));
1165        assert!(paths.contains(&&"/api".to_string()));
1166    }
1167
1168    #[tokio::test]
1169    async fn test_concurrent_router_merge_no_deadlock() {
1170        use crate::controller::{ControllerRoute, ElifController};
1171        use tokio::time::{timeout, Duration};
1172
1173        // Create test controllers
1174        struct TestControllerA;
1175        #[async_trait::async_trait]
1176        impl ElifController for TestControllerA {
1177            fn name(&self) -> &str {
1178                "TestControllerA"
1179            }
1180            fn base_path(&self) -> &str {
1181                "/a"
1182            }
1183            fn routes(&self) -> Vec<ControllerRoute> {
1184                vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1185            }
1186            async fn handle_request(
1187                self: std::sync::Arc<Self>,
1188                _method_name: String,
1189                _request: ElifRequest,
1190            ) -> HttpResult<ElifResponse> {
1191                Ok(ElifResponse::ok().text("A"))
1192            }
1193        }
1194
1195        struct TestControllerB;
1196        #[async_trait::async_trait]
1197        impl ElifController for TestControllerB {
1198            fn name(&self) -> &str {
1199                "TestControllerB"
1200            }
1201            fn base_path(&self) -> &str {
1202                "/b"
1203            }
1204            fn routes(&self) -> Vec<ControllerRoute> {
1205                vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1206            }
1207            async fn handle_request(
1208                self: std::sync::Arc<Self>,
1209                _method_name: String,
1210                _request: ElifRequest,
1211            ) -> HttpResult<ElifResponse> {
1212                Ok(ElifResponse::ok().text("B"))
1213            }
1214        }
1215
1216        // Test concurrent merging that could cause deadlock
1217        let task1 = tokio::spawn(async move {
1218            // Create fresh routers for concurrent merging test
1219            let a_copy = Router::<()>::new().controller(TestControllerA);
1220            let b_copy = Router::<()>::new().controller(TestControllerB);
1221            let _merged = a_copy.merge(b_copy);
1222        });
1223
1224        let task2 = tokio::spawn(async move {
1225            // This creates the reverse merge scenario
1226            let a_copy = Router::<()>::new().controller(TestControllerA);
1227            let b_copy = Router::<()>::new().controller(TestControllerB);
1228            let _merged = b_copy.merge(a_copy);
1229        });
1230
1231        // If there's a deadlock, this will timeout
1232        let result = timeout(Duration::from_millis(100), async {
1233            let _ = tokio::try_join!(task1, task2);
1234        })
1235        .await;
1236
1237        // Should complete without timing out (no deadlock)
1238        assert!(
1239            result.is_ok(),
1240            "Router merge operations should not deadlock"
1241        );
1242    }
1243
1244    #[test]
1245    fn test_controller_merge_preserves_all_controllers() {
1246        use crate::controller::{ControllerRoute, ElifController};
1247
1248        struct ControllerA;
1249        #[async_trait::async_trait]
1250        impl ElifController for ControllerA {
1251            fn name(&self) -> &str {
1252                "ControllerA"
1253            }
1254            fn base_path(&self) -> &str {
1255                "/a"
1256            }
1257            fn routes(&self) -> Vec<ControllerRoute> {
1258                vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1259            }
1260            async fn handle_request(
1261                self: std::sync::Arc<Self>,
1262                _method_name: String,
1263                _request: ElifRequest,
1264            ) -> HttpResult<ElifResponse> {
1265                Ok(ElifResponse::ok().text("A"))
1266            }
1267        }
1268
1269        struct ControllerB;
1270        #[async_trait::async_trait]
1271        impl ElifController for ControllerB {
1272            fn name(&self) -> &str {
1273                "ControllerB"
1274            }
1275            fn base_path(&self) -> &str {
1276                "/b"
1277            }
1278            fn routes(&self) -> Vec<ControllerRoute> {
1279                vec![ControllerRoute::new(HttpMethod::GET, "", "test")]
1280            }
1281            async fn handle_request(
1282                self: std::sync::Arc<Self>,
1283                _method_name: String,
1284                _request: ElifRequest,
1285            ) -> HttpResult<ElifResponse> {
1286                Ok(ElifResponse::ok().text("B"))
1287            }
1288        }
1289
1290        let router_a = Router::<()>::new().controller(ControllerA);
1291        let router_b = Router::<()>::new().controller(ControllerB);
1292
1293        let merged_router = router_a.merge(router_b);
1294
1295        // Verify both controllers are present in the merged registry
1296        let controller_registry = merged_router.controller_registry();
1297        let registry = controller_registry.lock().unwrap();
1298
1299        assert!(registry.get_controller("ControllerA").is_some());
1300        assert!(registry.get_controller("ControllerB").is_some());
1301
1302        // Verify controller names
1303        let names = registry.controller_names();
1304        assert_eq!(names.len(), 2);
1305        assert!(names.contains(&&"ControllerA".to_string()));
1306        assert!(names.contains(&&"ControllerB".to_string()));
1307    }
1308
1309    #[test]
1310    fn test_simple_nest_route_registration() {
1311        // Test basic nesting without middleware to understand route registration behavior
1312        let parent_router = Router::<()>::new().get("/parent", elif_handler);
1313
1314        let nested_router = Router::<()>::new().get("/nested", elif_handler);
1315
1316        // Check initial route counts
1317        assert_eq!(
1318            parent_router.registry().lock().unwrap().all_routes().len(),
1319            1
1320        );
1321        assert_eq!(
1322            nested_router.registry().lock().unwrap().all_routes().len(),
1323            1
1324        );
1325
1326        // Nest the routers
1327        let composed_router = parent_router.nest("/api", nested_router);
1328
1329        // Check final route count
1330        let route_count = composed_router
1331            .registry()
1332            .lock()
1333            .unwrap()
1334            .all_routes()
1335            .len();
1336
1337        // Verify that nesting merges route registries correctly
1338        // We expect the nested router's routes to be merged into the parent registry
1339        assert_eq!(
1340            route_count, 2,
1341            "Expected both parent and nested routes to be registered, got: {}",
1342            route_count
1343        );
1344    }
1345
1346    #[test]
1347    fn test_route_builder_with_middleware_groups() {
1348        use crate::middleware::v2::LoggingMiddleware;
1349        use std::sync::Arc;
1350
1351        // Create middleware groups
1352        let router = Router::<()>::new()
1353            .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1354            .middleware_group("auth", vec![Arc::new(LoggingMiddleware)])
1355            .route("/api/users")
1356            .use_group("api")
1357            .use_group("auth")
1358            .get(elif_handler);
1359
1360        // Verify middleware groups exist
1361        assert!(router.middleware_groups().contains_key("api"));
1362        assert!(router.middleware_groups().contains_key("auth"));
1363
1364        // Verify route middleware mappings exist
1365        assert_eq!(router.route_middleware().len(), 1);
1366
1367        // Check that the route was assigned the correct middleware groups
1368        let route_middleware = router.route_middleware().values().next().unwrap();
1369        assert_eq!(route_middleware.len(), 2);
1370        assert!(route_middleware.contains(&"api".to_string()));
1371        assert!(route_middleware.contains(&"auth".to_string()));
1372    }
1373
1374    #[test]
1375    fn test_route_builder_chaining() {
1376        use crate::middleware::v2::LoggingMiddleware;
1377        use std::sync::Arc;
1378
1379        let router = Router::<()>::new()
1380            .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1381            .route("/api/users")
1382            .use_group("api")
1383            .name("users.index")
1384            .get(elif_handler);
1385
1386        // Verify route was registered with correct name and middleware
1387        let binding = router.registry();
1388        let registry = binding.lock().unwrap();
1389        let routes: Vec<_> = registry.all_routes().values().collect();
1390        assert_eq!(routes.len(), 1);
1391
1392        let route = routes[0];
1393        assert_eq!(route.path, "/api/users");
1394        assert_eq!(route.name, Some("users.index".to_string()));
1395        assert_eq!(route.method, HttpMethod::GET);
1396    }
1397
1398    #[test]
1399    fn test_multiple_routes_with_different_middleware() {
1400        use crate::middleware::v2::{LoggingMiddleware, SimpleAuthMiddleware};
1401        use std::sync::Arc;
1402
1403        let router = Router::<()>::new()
1404            .middleware_group("api", vec![Arc::new(LoggingMiddleware)])
1405            .middleware_group(
1406                "auth",
1407                vec![Arc::new(SimpleAuthMiddleware::new("secret".to_string()))],
1408            )
1409            .route("/api/public")
1410            .use_group("api")
1411            .get(elif_handler)
1412            .route("/api/protected")
1413            .use_group("api")
1414            .use_group("auth")
1415            .get(elif_handler)
1416            .route("/api/admin")
1417            .use_group("auth")
1418            .get(elif_handler);
1419
1420        // Verify all routes were created
1421        assert_eq!(router.registry().lock().unwrap().all_routes().len(), 3);
1422
1423        // Verify route middleware mappings
1424        let route_middleware = router.route_middleware();
1425        assert_eq!(route_middleware.len(), 3);
1426
1427        // Check each route has correct middleware
1428        let middleware_counts: Vec<usize> = route_middleware.values().map(|v| v.len()).collect();
1429        middleware_counts
1430            .iter()
1431            .for_each(|&count| assert!(count > 0));
1432
1433        // Verify we have the right mix of middleware assignments
1434        let total_middleware_assignments: usize = middleware_counts.iter().sum();
1435        assert_eq!(total_middleware_assignments, 4); // 1 + 2 + 1 = 4 middleware assignments
1436    }
1437
1438    #[test]
1439    fn test_ioc_controller_registration() {
1440        use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1441        use elif_core::container::IocContainer;
1442        use elif_core::ServiceBinder;
1443        use std::sync::Arc;
1444
1445        // Test service for dependency injection
1446        #[derive(Default)]
1447        struct TestService {
1448            #[allow(dead_code)]
1449            name: String,
1450        }
1451
1452        unsafe impl Send for TestService {}
1453        unsafe impl Sync for TestService {}
1454
1455        // Test controller with dependency injection
1456        struct IocTestController {
1457            #[allow(dead_code)]
1458            service: Arc<TestService>,
1459        }
1460
1461        #[async_trait::async_trait]
1462        impl ElifController for IocTestController {
1463            fn name(&self) -> &str {
1464                "IocTestController"
1465            }
1466            fn base_path(&self) -> &str {
1467                "/ioc-test"
1468            }
1469
1470            fn routes(&self) -> Vec<ControllerRoute> {
1471                vec![
1472                    ControllerRoute::new(HttpMethod::GET, "", "list"),
1473                    ControllerRoute::new(HttpMethod::GET, "/{id}", "show"),
1474                ]
1475            }
1476
1477            async fn handle_request(
1478                self: Arc<Self>,
1479                method_name: String,
1480                _request: ElifRequest,
1481            ) -> HttpResult<ElifResponse> {
1482                match method_name.as_str() {
1483                    "list" => Ok(ElifResponse::ok().text("IoC List")),
1484                    "show" => Ok(ElifResponse::ok().text("IoC Show")),
1485                    _ => Ok(ElifResponse::not_found().text("Method not found")),
1486                }
1487            }
1488        }
1489
1490        impl IocControllable for IocTestController {
1491            fn from_ioc_container(
1492                container: &IocContainer,
1493                _scope: Option<&elif_core::container::ScopeId>,
1494            ) -> Result<Self, String> {
1495                let service = container
1496                    .resolve::<TestService>()
1497                    .map_err(|e| format!("Failed to resolve TestService: {}", e))?;
1498
1499                Ok(Self { service })
1500            }
1501        }
1502
1503        // Set up IoC container
1504        let mut container = IocContainer::new();
1505        container.bind::<TestService, TestService>();
1506        container.build().expect("Container build failed");
1507
1508        let container_arc = Arc::new(container);
1509
1510        // Create router with IoC container and register controller
1511        let router = Router::<()>::new()
1512            .with_ioc_container(Arc::clone(&container_arc))
1513            .controller_from_container::<IocTestController>();
1514
1515        // Verify routes were registered
1516        let registry = router.registry();
1517        let reg = registry.lock().unwrap();
1518        assert_eq!(reg.all_routes().len(), 2);
1519
1520        // Verify controller was registered in controller registry
1521        let controller_registry = router.controller_registry();
1522        let ctrl_reg = controller_registry.lock().unwrap();
1523        assert!(ctrl_reg.get_controller("IocTestController").is_some());
1524    }
1525
1526    #[test]
1527    #[should_panic(expected = "IoC container must be set before registering IoC controllers")]
1528    fn test_ioc_controller_without_container() {
1529        use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1530        use elif_core::container::IocContainer;
1531
1532        struct TestController;
1533
1534        #[async_trait::async_trait]
1535        impl ElifController for TestController {
1536            fn name(&self) -> &str {
1537                "TestController"
1538            }
1539            fn base_path(&self) -> &str {
1540                "/test"
1541            }
1542            fn routes(&self) -> Vec<ControllerRoute> {
1543                vec![]
1544            }
1545
1546            async fn handle_request(
1547                self: std::sync::Arc<Self>,
1548                _method_name: String,
1549                _request: ElifRequest,
1550            ) -> HttpResult<ElifResponse> {
1551                Ok(ElifResponse::ok().text("test"))
1552            }
1553        }
1554
1555        impl IocControllable for TestController {
1556            fn from_ioc_container(
1557                _container: &IocContainer,
1558                _scope: Option<&elif_core::container::ScopeId>,
1559            ) -> Result<Self, String> {
1560                Ok(Self)
1561            }
1562        }
1563
1564        // This should panic because no IoC container is set
1565        Router::<()>::new().controller_from_container::<TestController>();
1566    }
1567
1568    #[test]
1569    fn test_router_with_ioc_container() {
1570        use elif_core::container::IocContainer;
1571        use std::sync::Arc;
1572
1573        let container = Arc::new(IocContainer::new());
1574        let router = Router::<()>::new().with_ioc_container(Arc::clone(&container));
1575
1576        assert!(router.ioc_container().is_some());
1577        assert!(Arc::ptr_eq(router.ioc_container().unwrap(), &container));
1578    }
1579
1580    #[test]
1581    fn test_merge_preserves_ioc_container() {
1582        use elif_core::container::IocContainer;
1583        use std::sync::Arc;
1584
1585        let container = Arc::new(IocContainer::new());
1586
1587        let router1 = Router::<()>::new().with_ioc_container(Arc::clone(&container));
1588
1589        let router2 = Router::<()>::new();
1590
1591        let merged = router1.merge(router2);
1592
1593        // Should preserve router1's container
1594        assert!(merged.ioc_container().is_some());
1595        assert!(Arc::ptr_eq(merged.ioc_container().unwrap(), &container));
1596    }
1597
1598    #[test]
1599    fn test_merge_prefers_first_container() {
1600        use elif_core::container::IocContainer;
1601        use std::sync::Arc;
1602
1603        let container1 = Arc::new(IocContainer::new());
1604        let container2 = Arc::new(IocContainer::new());
1605
1606        let router1 = Router::<()>::new().with_ioc_container(Arc::clone(&container1));
1607
1608        let router2 = Router::<()>::new().with_ioc_container(Arc::clone(&container2));
1609
1610        let merged = router1.merge(router2);
1611
1612        // Should prefer router1's container
1613        assert!(merged.ioc_container().is_some());
1614        assert!(Arc::ptr_eq(merged.ioc_container().unwrap(), &container1));
1615    }
1616
1617    #[test]
1618    fn test_scoped_controller_registration() {
1619        use crate::controller::{factory::IocControllable, ControllerRoute, ElifController};
1620        use elif_core::container::IocContainer;
1621        use elif_core::ServiceBinder;
1622        use std::sync::Arc;
1623
1624        #[derive(Default)]
1625        struct ScopedService {
1626            #[allow(dead_code)]
1627            id: String,
1628        }
1629
1630        unsafe impl Send for ScopedService {}
1631        unsafe impl Sync for ScopedService {}
1632
1633        struct ScopedController {
1634            #[allow(dead_code)]
1635            service: Arc<ScopedService>,
1636        }
1637
1638        #[async_trait::async_trait]
1639        impl ElifController for ScopedController {
1640            fn name(&self) -> &str {
1641                "ScopedController"
1642            }
1643            fn base_path(&self) -> &str {
1644                "/scoped"
1645            }
1646
1647            fn routes(&self) -> Vec<ControllerRoute> {
1648                vec![ControllerRoute::new(HttpMethod::GET, "/test", "test")]
1649            }
1650
1651            async fn handle_request(
1652                self: Arc<Self>,
1653                _method_name: String,
1654                _request: ElifRequest,
1655            ) -> HttpResult<ElifResponse> {
1656                Ok(ElifResponse::ok().text("Scoped"))
1657            }
1658        }
1659
1660        impl IocControllable for ScopedController {
1661            fn from_ioc_container(
1662                container: &IocContainer,
1663                _scope: Option<&elif_core::container::ScopeId>,
1664            ) -> Result<Self, String> {
1665                let service = container
1666                    .resolve::<ScopedService>()
1667                    .map_err(|e| format!("Failed to resolve ScopedService: {}", e))?;
1668
1669                Ok(Self { service })
1670            }
1671        }
1672
1673        // Set up IoC container
1674        let mut container = IocContainer::new();
1675        container.bind::<ScopedService, ScopedService>();
1676        container.build().expect("Container build failed");
1677
1678        let container_arc = Arc::new(container);
1679
1680        // Create router with scoped controller
1681        let router = Router::<()>::new()
1682            .with_ioc_container(Arc::clone(&container_arc))
1683            .scoped_controller_from_container::<ScopedController>();
1684
1685        // Verify routes were registered
1686        let registry = router.registry();
1687        let reg = registry.lock().unwrap();
1688        assert_eq!(reg.all_routes().len(), 1);
1689
1690        // Verify controller was registered
1691        let controller_registry = router.controller_registry();
1692        let ctrl_reg = controller_registry.lock().unwrap();
1693        assert!(ctrl_reg.get_controller("ScopedController").is_some());
1694    }
1695
1696    #[test]
1697    fn test_route_without_middleware_groups() {
1698        let router = Router::<()>::new().route("/simple").get(elif_handler);
1699
1700        // Verify route was created without middleware groups
1701        let binding = router.registry();
1702        let registry = binding.lock().unwrap();
1703        assert_eq!(registry.all_routes().len(), 1);
1704
1705        let route_middleware = router.route_middleware();
1706        assert_eq!(route_middleware.len(), 1);
1707
1708        // The route should have empty middleware groups list
1709        let middleware_groups = route_middleware.values().next().unwrap();
1710        assert_eq!(middleware_groups.len(), 0);
1711    }
1712}
1713
1714#[cfg(test)]
1715mod integration_tests {
1716    use super::*;
1717    use crate::middleware::v2::{Middleware, Next, NextFuture};
1718    use crate::response::ElifResponse;
1719    use serde_json::json;
1720    use std::collections::HashMap;
1721    use std::sync::{Arc, Mutex};
1722
1723    /// Test middleware that adds headers to verify execution
1724    #[derive(Debug, Clone)]
1725    struct HeaderTestMiddleware {
1726        name: String,
1727        counter: Arc<Mutex<usize>>,
1728    }
1729
1730    impl HeaderTestMiddleware {
1731        fn new(name: &str) -> Self {
1732            Self {
1733                name: name.to_string(),
1734                counter: Arc::new(Mutex::new(0)),
1735            }
1736        }
1737    }
1738
1739    impl Middleware for HeaderTestMiddleware {
1740        fn handle(&self, mut request: ElifRequest, next: Next) -> NextFuture<'static> {
1741            let name = self.name.clone();
1742            let counter = self.counter.clone();
1743
1744            Box::pin(async move {
1745                // Increment counter to track execution
1746                {
1747                    let mut count = counter.lock().unwrap();
1748                    *count += 1;
1749                }
1750
1751                // Add request header to track middleware execution
1752                let header_name = crate::response::headers::ElifHeaderName::from_str(&format!(
1753                    "x-middleware-{}",
1754                    name.to_lowercase()
1755                ))
1756                .unwrap();
1757                let header_value =
1758                    crate::response::headers::ElifHeaderValue::from_str("executed").unwrap();
1759                request.headers.insert(header_name, header_value);
1760
1761                // Call next in chain
1762                let response = next.run(request).await;
1763
1764                // Add response header to verify middleware ran after handler
1765                let response_header = format!("x-response-{}", name.to_lowercase());
1766                response
1767                    .header(&response_header, "executed")
1768                    .unwrap_or_else(|_| {
1769                        // Return original response if header addition fails
1770                        ElifResponse::ok().text("Middleware executed")
1771                    })
1772            })
1773        }
1774
1775        fn name(&self) -> &'static str {
1776            // Return static string for consistency in tests - we need to leak the string to make it 'static
1777            match self.name.as_str() {
1778                "Parent" => "Parent",
1779                "Nested" => "Nested",
1780                "Global" => "Global",
1781                "First" => "First",
1782                "Second" => "Second",
1783                "Third" => "Third",
1784                "Router1" => "Router1",
1785                "Router2" => "Router2",
1786                _ => "TestMiddleware",
1787            }
1788        }
1789    }
1790
1791    // Simple test handlers
1792    async fn test_handler(request: ElifRequest) -> HttpResult<ElifResponse> {
1793        // Return headers from request so we can verify middleware execution
1794        let mut response_headers = HashMap::new();
1795
1796        for (key, value) in request.headers.iter() {
1797            let key_str = key.as_str().to_string();
1798            if let Ok(value_str) = value.to_str() {
1799                response_headers.insert(key_str, value_str.to_string());
1800            }
1801        }
1802
1803        Ok(ElifResponse::ok().json(&json!({
1804            "message": "Hello from handler",
1805            "request_headers": response_headers,
1806            "path": request.path()
1807        }))?)
1808    }
1809
1810    async fn nested_handler(request: ElifRequest) -> HttpResult<ElifResponse> {
1811        Ok(ElifResponse::ok().json(&json!({
1812            "message": "Hello from nested handler",
1813            "path": request.path()
1814        }))?)
1815    }
1816
1817    #[tokio::test]
1818    async fn test_global_middleware_execution() {
1819        // Create middleware that we can verify execution for
1820        let test_middleware = HeaderTestMiddleware::new("Global");
1821        let middleware_counter = test_middleware.counter.clone();
1822
1823        // Create router with global middleware
1824        let router = Router::<()>::new()
1825            .use_middleware(test_middleware)
1826            .get("/test", test_handler);
1827
1828        // Verify middleware is in the pipeline
1829        assert_eq!(router.middleware_pipeline().len(), 1);
1830        assert_eq!(router.middleware_pipeline().names(), vec!["Global"]);
1831
1832        // Verify counter starts at 0
1833        assert_eq!(middleware_counter.lock().unwrap().clone(), 0);
1834
1835        // Test middleware execution through pipeline (unit test style)
1836        let request = ElifRequest::new(
1837            crate::request::ElifMethod::GET,
1838            "/test".parse().unwrap(),
1839            crate::response::headers::ElifHeaderMap::new(),
1840        );
1841
1842        let response = router
1843            .middleware_pipeline()
1844            .execute(request, |req| {
1845                Box::pin(async move {
1846                    // Verify middleware added the header
1847                    let header_name =
1848                        crate::response::headers::ElifHeaderName::from_str("x-middleware-global")
1849                            .unwrap();
1850                    assert!(req.headers.contains_key(&header_name));
1851                    ElifResponse::ok().text("Pipeline test response")
1852                })
1853            })
1854            .await;
1855
1856        // Verify middleware was executed once
1857        assert_eq!(middleware_counter.lock().unwrap().clone(), 1);
1858        assert_eq!(
1859            response.status_code(),
1860            crate::response::status::ElifStatusCode::OK
1861        );
1862    }
1863
1864    #[tokio::test]
1865    async fn test_nested_router_middleware_isolation() {
1866        // Create different middleware for parent and nested routers
1867        let parent_middleware = HeaderTestMiddleware::new("Parent");
1868        let nested_middleware = HeaderTestMiddleware::new("Nested");
1869
1870        let parent_counter = parent_middleware.counter.clone();
1871        let nested_counter = nested_middleware.counter.clone();
1872
1873        // Create parent router with its middleware
1874        let parent_router = Router::<()>::new()
1875            .use_middleware(parent_middleware)
1876            .get("/parent", test_handler);
1877
1878        // Create nested router with different middleware
1879        let nested_router = Router::<()>::new()
1880            .use_middleware(nested_middleware)
1881            .get("/nested", nested_handler);
1882
1883        // Compose the routers
1884        let composed_router = parent_router.nest("/api", nested_router);
1885
1886        // Verify structure
1887        assert_eq!(composed_router.middleware_pipeline().len(), 1); // Only parent middleware in global
1888        assert_eq!(
1889            composed_router.middleware_pipeline().names(),
1890            vec!["Parent"]
1891        );
1892
1893        // Test that both middleware start with 0 executions
1894        assert_eq!(parent_counter.lock().unwrap().clone(), 0);
1895        assert_eq!(nested_counter.lock().unwrap().clone(), 0);
1896
1897        // Test middleware isolation by manually executing pipelines
1898
1899        // 1. Test parent route - should only execute parent middleware
1900        let parent_request = ElifRequest::new(
1901            crate::request::ElifMethod::GET,
1902            "/parent".parse().unwrap(),
1903            crate::response::headers::ElifHeaderMap::new(),
1904        );
1905
1906        let parent_response = composed_router
1907            .middleware_pipeline()
1908            .execute(parent_request, |req| {
1909                Box::pin(async move {
1910                    // Should have parent middleware header, not nested
1911                    let parent_header =
1912                        crate::response::headers::ElifHeaderName::from_str("x-middleware-parent")
1913                            .unwrap();
1914                    let nested_header =
1915                        crate::response::headers::ElifHeaderName::from_str("x-middleware-nested")
1916                            .unwrap();
1917                    assert!(req.headers.contains_key(&parent_header));
1918                    assert!(!req.headers.contains_key(&nested_header));
1919                    ElifResponse::ok().text("Parent response")
1920                })
1921            })
1922            .await;
1923
1924        assert_eq!(
1925            parent_response.status_code(),
1926            crate::response::status::ElifStatusCode::OK
1927        );
1928        assert_eq!(parent_counter.lock().unwrap().clone(), 1);
1929        assert_eq!(nested_counter.lock().unwrap().clone(), 0); // Nested middleware should not execute
1930
1931        // Note: Testing nested route middleware execution would require integration with Axum
1932        // The structural test above verifies that the middleware scoping is set up correctly
1933        // Runtime testing would require a full HTTP server setup
1934    }
1935
1936    #[tokio::test]
1937    async fn test_middleware_execution_order() {
1938        // Create middleware with execution tracking
1939        let first_middleware = HeaderTestMiddleware::new("First");
1940        let second_middleware = HeaderTestMiddleware::new("Second");
1941        let third_middleware = HeaderTestMiddleware::new("Third");
1942
1943        let first_counter = first_middleware.counter.clone();
1944        let second_counter = second_middleware.counter.clone();
1945        let third_counter = third_middleware.counter.clone();
1946
1947        // Create router with multiple middleware
1948        let router = Router::<()>::new()
1949            .use_middleware(first_middleware)
1950            .use_middleware(second_middleware)
1951            .use_middleware(third_middleware)
1952            .get("/test", test_handler);
1953
1954        // Verify all middleware are in pipeline
1955        assert_eq!(router.middleware_pipeline().len(), 3);
1956        assert_eq!(
1957            router.middleware_pipeline().names(),
1958            vec!["First", "Second", "Third"]
1959        );
1960
1961        // Execute through pipeline
1962        let request = ElifRequest::new(
1963            crate::request::ElifMethod::GET,
1964            "/test".parse().unwrap(),
1965            crate::response::headers::ElifHeaderMap::new(),
1966        );
1967
1968        let response = router
1969            .middleware_pipeline()
1970            .execute(request, |req| {
1971                Box::pin(async move {
1972                    // All middleware should have executed and added headers
1973                    let first_header =
1974                        crate::response::headers::ElifHeaderName::from_str("x-middleware-first")
1975                            .unwrap();
1976                    let second_header =
1977                        crate::response::headers::ElifHeaderName::from_str("x-middleware-second")
1978                            .unwrap();
1979                    let third_header =
1980                        crate::response::headers::ElifHeaderName::from_str("x-middleware-third")
1981                            .unwrap();
1982                    assert!(req.headers.contains_key(&first_header));
1983                    assert!(req.headers.contains_key(&second_header));
1984                    assert!(req.headers.contains_key(&third_header));
1985
1986                    ElifResponse::ok().text("Handler executed after all middleware")
1987                })
1988            })
1989            .await;
1990
1991        // Verify all middleware executed exactly once
1992        assert_eq!(first_counter.lock().unwrap().clone(), 1);
1993        assert_eq!(second_counter.lock().unwrap().clone(), 1);
1994        assert_eq!(third_counter.lock().unwrap().clone(), 1);
1995        assert_eq!(
1996            response.status_code(),
1997            crate::response::status::ElifStatusCode::OK
1998        );
1999    }
2000
2001    #[tokio::test]
2002    async fn test_router_merge_middleware_execution() {
2003        // Create different middleware for each router
2004        let router1_middleware = HeaderTestMiddleware::new("Router1");
2005        let router2_middleware = HeaderTestMiddleware::new("Router2");
2006
2007        let router1_counter = router1_middleware.counter.clone();
2008        let router2_counter = router2_middleware.counter.clone();
2009
2010        // Create two routers with different middleware
2011        let router1 = Router::<()>::new()
2012            .use_middleware(router1_middleware)
2013            .get("/router1", test_handler);
2014
2015        let router2 = Router::<()>::new()
2016            .use_middleware(router2_middleware)
2017            .get("/router2", test_handler);
2018
2019        // Merge the routers
2020        let merged_router = router1.merge(router2);
2021
2022        // Verify merged middleware pipeline contains both middleware
2023        assert_eq!(merged_router.middleware_pipeline().len(), 2);
2024        assert_eq!(
2025            merged_router.middleware_pipeline().names(),
2026            vec!["Router1", "Router2"]
2027        );
2028
2029        // Test execution through merged pipeline
2030        let request = ElifRequest::new(
2031            crate::request::ElifMethod::GET,
2032            "/test".parse().unwrap(),
2033            crate::response::headers::ElifHeaderMap::new(),
2034        );
2035
2036        let response = merged_router
2037            .middleware_pipeline()
2038            .execute(request, |req| {
2039                Box::pin(async move {
2040                    // Both router middleware should have executed
2041                    let router1_header =
2042                        crate::response::headers::ElifHeaderName::from_str("x-middleware-router1")
2043                            .unwrap();
2044                    let router2_header =
2045                        crate::response::headers::ElifHeaderName::from_str("x-middleware-router2")
2046                            .unwrap();
2047                    assert!(req.headers.contains_key(&router1_header));
2048                    assert!(req.headers.contains_key(&router2_header));
2049
2050                    ElifResponse::ok().text("Merged router response")
2051                })
2052            })
2053            .await;
2054
2055        // Verify both middleware executed
2056        assert_eq!(router1_counter.lock().unwrap().clone(), 1);
2057        assert_eq!(router2_counter.lock().unwrap().clone(), 1);
2058        assert_eq!(
2059            response.status_code(),
2060            crate::response::status::ElifStatusCode::OK
2061        );
2062    }
2063
2064    #[tokio::test]
2065    async fn test_middleware_with_early_return() {
2066        /// Middleware that returns early based on a condition
2067        #[derive(Debug)]
2068        struct AuthMiddleware {
2069            required_token: String,
2070        }
2071
2072        impl AuthMiddleware {
2073            fn new(token: String) -> Self {
2074                Self {
2075                    required_token: token,
2076                }
2077            }
2078        }
2079
2080        impl Middleware for AuthMiddleware {
2081            fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
2082                let required_token = self.required_token.clone();
2083                Box::pin(async move {
2084                    // Check authorization header
2085                    let auth_header = request
2086                        .header("authorization")
2087                        .and_then(|h| h.to_str().ok());
2088
2089                    match auth_header {
2090                        Some(header) if header.starts_with("Bearer ") => {
2091                            let token = &header[7..];
2092                            if token == required_token {
2093                                // Token is valid, proceed
2094                                next.run(request).await
2095                            } else {
2096                                // Invalid token, return early
2097                                ElifResponse::unauthorized().json_value(json!({
2098                                    "error": {
2099                                        "code": "invalid_token",
2100                                        "message": "Invalid authorization token"
2101                                    }
2102                                }))
2103                            }
2104                        }
2105                        _ => {
2106                            // Missing or malformed auth header
2107                            ElifResponse::unauthorized().json_value(json!({
2108                                "error": {
2109                                    "code": "missing_token",
2110                                    "message": "Authorization header required"
2111                                }
2112                            }))
2113                        }
2114                    }
2115                })
2116            }
2117
2118            fn name(&self) -> &'static str {
2119                "AuthMiddleware"
2120            }
2121        }
2122
2123        // Create router with auth middleware
2124        let router = Router::<()>::new()
2125            .use_middleware(AuthMiddleware::new("secret123".to_string()))
2126            .get("/protected", test_handler);
2127
2128        // Test request without auth header (should return early)
2129        let request_no_auth = ElifRequest::new(
2130            crate::request::ElifMethod::GET,
2131            "/protected".parse().unwrap(),
2132            crate::response::headers::ElifHeaderMap::new(),
2133        );
2134
2135        let response_no_auth = router
2136            .middleware_pipeline()
2137            .execute(request_no_auth, |_req| {
2138                Box::pin(async move {
2139                    // This handler should NOT be called due to early return
2140                    panic!("Handler should not be called when auth fails");
2141                })
2142            })
2143            .await;
2144
2145        assert_eq!(
2146            response_no_auth.status_code(),
2147            crate::response::status::ElifStatusCode::UNAUTHORIZED
2148        );
2149
2150        // Test request with valid auth header (should proceed to handler)
2151        let mut headers = crate::response::headers::ElifHeaderMap::new();
2152        let auth_header =
2153            crate::response::headers::ElifHeaderName::from_str("authorization").unwrap();
2154        let auth_value =
2155            crate::response::headers::ElifHeaderValue::from_str("Bearer secret123").unwrap();
2156        headers.insert(auth_header, auth_value);
2157        let request_valid_auth = ElifRequest::new(
2158            crate::request::ElifMethod::GET,
2159            "/protected".parse().unwrap(),
2160            headers,
2161        );
2162
2163        let response_valid_auth = router
2164            .middleware_pipeline()
2165            .execute(request_valid_auth, |req| {
2166                Box::pin(async move {
2167                    // Handler should be called with valid auth
2168                    assert!(req.header("authorization").is_some());
2169                    ElifResponse::ok().text("Protected content accessed")
2170                })
2171            })
2172            .await;
2173
2174        assert_eq!(
2175            response_valid_auth.status_code(),
2176            crate::response::status::ElifStatusCode::OK
2177        );
2178
2179        // Test request with invalid auth token (should return early)
2180        let mut headers = crate::response::headers::ElifHeaderMap::new();
2181        let auth_header =
2182            crate::response::headers::ElifHeaderName::from_str("authorization").unwrap();
2183        let auth_value =
2184            crate::response::headers::ElifHeaderValue::from_str("Bearer invalid").unwrap();
2185        headers.insert(auth_header, auth_value);
2186        let request_invalid_auth = ElifRequest::new(
2187            crate::request::ElifMethod::GET,
2188            "/protected".parse().unwrap(),
2189            headers,
2190        );
2191
2192        let response_invalid_auth = router
2193            .middleware_pipeline()
2194            .execute(request_invalid_auth, |_req| {
2195                Box::pin(async move {
2196                    // Handler should NOT be called with invalid token
2197                    panic!("Handler should not be called when auth token is invalid");
2198                })
2199            })
2200            .await;
2201
2202        assert_eq!(
2203            response_invalid_auth.status_code(),
2204            crate::response::status::ElifStatusCode::UNAUTHORIZED
2205        );
2206    }
2207}
2208
2209/// Create a controller handler function
2210pub fn controller_handler<C>(
2211    controller: Arc<C>,
2212    method_name: String,
2213) -> impl Fn(ElifRequest) -> Pin<Box<dyn Future<Output = HttpResult<ElifResponse>> + Send>>
2214       + Clone
2215       + Send
2216       + Sync
2217       + 'static
2218where
2219    C: ElifController + 'static,
2220{
2221    move |request: ElifRequest| {
2222        let controller = Arc::clone(&controller);
2223        let method_name = method_name.clone();
2224
2225        Box::pin(async move { controller.handle_request(method_name, request).await })
2226    }
2227}
2228
2229/// Registry for managing registered controllers
2230pub struct ControllerRegistry {
2231    controllers: HashMap<String, Arc<dyn ElifController>>,
2232}
2233
2234impl std::fmt::Debug for ControllerRegistry {
2235    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2236        f.debug_struct("ControllerRegistry")
2237            .field(
2238                "controllers",
2239                &format!("{} controllers", self.controllers.len()),
2240            )
2241            .finish()
2242    }
2243}
2244
2245impl Default for ControllerRegistry {
2246    fn default() -> Self {
2247        Self::new()
2248    }
2249}
2250
2251impl ControllerRegistry {
2252    pub fn new() -> Self {
2253        Self {
2254            controllers: HashMap::new(),
2255        }
2256    }
2257
2258    pub fn register(&mut self, name: String, controller: Arc<dyn ElifController>) {
2259        self.controllers.insert(name, controller);
2260    }
2261
2262    pub fn get_controller(&self, name: &str) -> Option<&Arc<dyn ElifController>> {
2263        self.controllers.get(name)
2264    }
2265
2266    pub fn all_controllers(&self) -> impl Iterator<Item = (&String, &Arc<dyn ElifController>)> {
2267        self.controllers.iter()
2268    }
2269
2270    pub fn controller_names(&self) -> Vec<&String> {
2271        self.controllers.keys().collect()
2272    }
2273}
2274
2275/// Create a scoped IoC controller handler that creates a new scope per request
2276pub fn scoped_ioc_controller_handler<C>(
2277    container: Arc<IocContainer>,
2278    method_name: String,
2279) -> impl Fn(ElifRequest) -> Pin<Box<dyn Future<Output = HttpResult<ElifResponse>> + Send>>
2280       + Clone
2281       + Send
2282       + Sync
2283       + 'static
2284where
2285    C: ElifController + IocControllable + 'static,
2286{
2287    move |request: ElifRequest| {
2288        let container = Arc::clone(&container);
2289        let method_name = method_name.clone();
2290
2291        Box::pin(async move {
2292            // Create a new scope for this request
2293            let scope_id =
2294                container
2295                    .create_scope()
2296                    .map_err(|e| crate::errors::HttpError::InternalError {
2297                        message: format!("Failed to create request scope: {}", e),
2298                    })?;
2299
2300            // Resolve controller with scoped dependencies
2301            let controller = C::from_ioc_container(&container, Some(&scope_id)).map_err(|e| {
2302                crate::errors::HttpError::InternalError {
2303                    message: format!("Failed to resolve scoped controller: {}", e),
2304                }
2305            })?;
2306
2307            let controller_arc = Arc::new(controller);
2308            let result = controller_arc.handle_request(method_name, request).await;
2309
2310            // Clean up the scope (fire and forget - don't block response)
2311            let container_clone = Arc::clone(&container);
2312            tokio::spawn(async move {
2313                if let Err(e) = container_clone.dispose_scope(&scope_id).await {
2314                    eprintln!("Failed to dispose request scope: {}", e);
2315                }
2316            });
2317
2318            result
2319        })
2320    }
2321}