import { jsx, jsxs } from "react/jsx-runtime";
import react, { createContext, useContext } from "react";
import { get, set } from "lodash";
import { Outlet, RouterProvider, createBrowserRouter, createHashRouter, createMemoryRouter, useRouteError } from "react-router-dom";
import VariablesProvider from "../variables/VariablesProvider.mjs";
import { BlankComponent, RouterContextCleaner } from "./components/index.mjs";
import { CustomRouterContextProvider } from "./CustomRouterContextProvider.mjs";
function _define_property(obj, key, value) {
    if (key in obj) Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
    });
    else obj[key] = value;
    return obj;
}
class RouterManager {
    get basename() {
        return this.router.basename;
    }
    get state() {
        return this.router.state;
    }
    get navigate() {
        return this.router.navigate;
    }
    getRoutesTree() {
        const routes = {};
        for (const [name, route] of Object.entries(this.routes))set(routes, name.split('.').join('.children.'), {
            ...get(routes, name.split('.').join('.children.')),
            ...route
        });
        const buildRoutesTree = (routes)=>Object.values(routes).reduce((acc, item)=>{
                if (1 === Object.keys(item).length && item.children) acc.push(...buildRoutesTree(item.children));
                else {
                    const { Component, element, children, ...reset } = item;
                    let ele = element;
                    if (Component) ele = 'string' == typeof Component ? this.app.renderComponent(Component) : /*#__PURE__*/ react.createElement(Component);
                    const res = {
                        ...reset,
                        element: ele,
                        children: children ? buildRoutesTree(children) : void 0
                    };
                    acc.push(res);
                }
                return acc;
            }, []);
        return buildRoutesTree(routes);
    }
    getRoutes() {
        return this.routes;
    }
    setType(type) {
        this.options.type = type;
    }
    getBasename() {
        return this.options.basename;
    }
    setBasename(basename) {
        this.options.basename = basename;
    }
    getRouterComponent(children) {
        const { type = 'browser', ...opts } = this.options;
        const routerCreators = {
            hash: createHashRouter,
            browser: createBrowserRouter,
            memory: createMemoryRouter
        };
        const routes = this.getRoutesTree();
        const BaseLayoutContext = /*#__PURE__*/ createContext(null);
        const Provider = ()=>{
            const BaseLayout = useContext(BaseLayoutContext);
            return /*#__PURE__*/ jsx(CustomRouterContextProvider, {
                children: /*#__PURE__*/ jsx(BaseLayout, {
                    children: /*#__PURE__*/ jsxs(VariablesProvider, {
                        children: [
                            /*#__PURE__*/ jsx(Outlet, {}),
                            children
                        ]
                    })
                })
            });
        };
        const ErrorElement = ()=>{
            const error = useRouteError();
            throw error;
        };
        this.router = routerCreators[type]([
            {
                element: /*#__PURE__*/ jsx(Provider, {}),
                errorElement: /*#__PURE__*/ jsx(ErrorElement, {}),
                children: routes
            }
        ], opts);
        const RenderRouter = (param)=>{
            let { BaseLayout = BlankComponent } = param;
            return /*#__PURE__*/ jsx(BaseLayoutContext.Provider, {
                value: BaseLayout,
                children: /*#__PURE__*/ jsx(RouterContextCleaner, {
                    children: /*#__PURE__*/ jsx(RouterProvider, {
                        router: this.router
                    })
                })
            });
        };
        return RenderRouter;
    }
    add(name, route) {
        this.routes[name] = route;
    }
    get(name) {
        return this.routes[name];
    }
    has(name) {
        return !!this.get(name);
    }
    remove(name) {
        delete this.routes[name];
    }
    constructor(options = {}, app){
        _define_property(this, "routes", {});
        _define_property(this, "options", void 0);
        _define_property(this, "app", void 0);
        _define_property(this, "router", void 0);
        this.options = options;
        this.app = app;
        this.routes = options.routes || {};
    }
}
function createRouterManager(options, app) {
    return new RouterManager(options, app);
}
export { RouterManager, createRouterManager };
