use crate::collections::LinearMap;
use crate::core::router::handlers::ApiHandler;
use crate::core::router::Path;
use crate::core::router::RouteNode;
use crate::core::router::builder::types::{LayoutDefinition, ApiDefinition, PageDefinition, GroupDefinition};

#[derive(Clone, Debug)]
pub struct Router {
    pub root_nodes: Vec<RouteNode>,
}

impl Router {
    pub fn new() -> Self {
        Self { root_nodes: Vec::new() }
    }

    // --- Core Builders ---

    pub fn page<P, F>(mut self, path: P, f: F) -> Self
    where 
        P: Into<String>,
        F: FnOnce(PageDefinition) -> PageDefinition 
    {
        let page = PageDefinition {
            path: Path::from_str(&path.into()),
            controllers: LinearMap::new(),
            error_controller: None,
            loader_controller: None,
            middlewares: Vec::new(),
            metadata: None,
            children: Vec::new(),
        };

        let final_page = f(page);
        self.root_nodes.push(final_page.into_route_node());
        self
    }

    pub fn api<P, F>(mut self, path: P, f: F) -> Self 
    where
        P: Into<String>,
        F: FnOnce(ApiDefinition) -> ApiDefinition
    {
        let api = ApiDefinition {
            path: Path::from_str(&path.into()),
            controllers: LinearMap::new(),
            children: Vec::new(),
            middlewares: Vec::new(),
        };

        let final_api = f(api);
        self.root_nodes.push(final_api.into_route_node());
        self
    }

    pub fn layout<I, F>(mut self, id: I, f: F) -> Self
    where
        I: Into<String>,
        F: FnOnce(LayoutDefinition) -> LayoutDefinition
    {
        let layout = LayoutDefinition {
            id: id.into(),
            controller: None,
            error_controller: None,
            loader_controller: None,
            parallel_routes: LinearMap::new(),
            metadata: None,
            children: Vec::new(),
            middlewares: Vec::new(),
        };

        let final_layout = f(layout);
        self.root_nodes.push(final_layout.into_route_node());
        self
    }

    pub fn group<I, F>(mut self, id: I, f: F) -> Self
    where
        I: Into<String>,
        F: FnOnce(GroupDefinition) -> GroupDefinition
    {
        let group = GroupDefinition {
            id: id.into(),
            children: Vec::new(),
            middlewares: Vec::new(),
            metadata: None,
        };

        let final_group = f(group);
        self.root_nodes.push(final_group.into_route_node());
        self
    }

    pub fn nest<P>(mut self, path: P, mut router: Router) -> Self 
    where
        P: Into<String>
    {
        // 1. Structuralize the prefix string into a real Path object
        let prefix_path = Path::from_str(&path.into());

        // 2. Recursively traverse and mutate all nodes inside the target router
        for node in &mut router.root_nodes {
            Self::prepend_prefix_to_node(node, &prefix_path);
        }

        // 3. Move the modified nodes into this router's root inventory
        self.root_nodes.extend(router.root_nodes);
        self
    }

    pub fn children<F>(mut self, f: F) -> Self 
    where 
        F: FnOnce(Router) -> Router 
    {
        let final_router = f(Router::new());
        self.root_nodes.extend(final_router.root_nodes);
        self
    }

    // --- HTTP Verb Shorthands (Axum/Express Style) ---
    // These delegate entirely to the `.api()` builder to prevent code duplication.

    pub fn get<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("GET", handler))
    }

    pub fn post<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("POST", handler))
    }

    pub fn put<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("PUT", handler))
    }

    pub fn delete<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("DELETE", handler))
    }

    pub fn patch<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("PATCH", handler))
    }

    pub fn head<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("HEAD", handler))
    }

    pub fn options<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("OPTIONS", handler))
    }

    pub fn trace<P, H, Args>(self, path: P, handler: H) -> Self
    where
        P: Into<String>,
        H: ApiHandler<Args> + Clone + Send + Sync + 'static,
        Args: 'static + Clone + Send + Sync,
    {
        self.api(path, |api| api.method("TRACE", handler))
    }
}


impl Router {
    /// Internal recursive function to walk down the RouteNode tree.
    fn prepend_prefix_to_node(node: &mut RouteNode, prefix: &Path) {
        match node {
            RouteNode::Page { path, children, .. } => {
                // Mutate path via our clean structural API
                path.prepend(prefix);
                
                // Recurse down any children nested under this page
                for child in children {
                    Self::prepend_prefix_to_node(child, prefix);
                }
            }
            
            RouteNode::Api { path, children, .. } => {
                // Mutate path via our clean structural API
                path.prepend(prefix);
                
                // Recurse down any children nested under this API route
                for child in children {
                    Self::prepend_prefix_to_node(child, prefix);
                }
            }
            
            RouteNode::Layout { children, .. } => {
                // Layouts don't own a path component, but their children definitely do!
                for child in children {
                    Self::prepend_prefix_to_node(child, prefix);
                }
                
                // you would iterate over and mutate them here as well.
            }
            
            RouteNode::Group { children, .. } => {
                // Route Groups don't impact paths directly, pass prefix down to children
                for child in children {
                    Self::prepend_prefix_to_node(child, prefix);
                }
            }
        }
    }
}