use crate::{cfg::RouterCfg, RouterCore};
use dioxus::prelude::*;
use std::sync::Arc;

/// The props for the [`Router`](fn.Router.html) component.
#[derive(Props)]
pub struct RouterProps<'a> {
    /// The routes and elements that should be rendered when the path matches.
    ///
    /// If elements are not contained within Routes, the will be rendered
    /// regardless of the path.
    pub children: Element<'a>,

    /// The URL to point at
    ///
    /// This will be used to trim any latent segments from the URL when your app is
    /// not deployed to the root of the domain.
    pub base_url: Option<&'a str>,

    /// Hook into the router when the route is changed.
    ///
    /// This lets you easily implement redirects
    #[props(default)]
    pub onchange: EventHandler<'a, Arc<RouterCore>>,

    /// Set the active class of all Link components contained in this router.
    ///
    /// This is useful if you don't want to repeat the same `active_class` prop value in every Link.
    /// By default set to `"active"`.
    pub active_class: Option<&'a str>,

    /// Set the initial url.
    pub initial_url: Option<String>,
}

/// A component that conditionally renders children based on the current location of the app.
///
/// Uses BrowserRouter in the browser and HashRouter everywhere else.
///
/// Will fallback to HashRouter is BrowserRouter is not available, or through configuration.
#[allow(non_snake_case)]
pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element {
    let svc = cx.use_hook(|| {
        cx.provide_context(RouterCore::new(
            &cx,
            RouterCfg {
                base_url: cx.props.base_url.map(|s| s.to_string()),
                active_class: cx.props.active_class.map(|s| s.to_string()),
                initial_url: cx.props.initial_url.clone(),
            },
        ))
    });

    // next time we run the rout_found will be filled
    if svc.route_found.get().is_none() {
        cx.props.onchange.call(svc.clone());
    }

    cx.render(rsx!(&cx.props.children))
}
