import { addPagesFromContext, addWidgetsFromContext } from "@insite/client-framework/Components/ContentItemStore";
import translate from "@insite/client-framework/Translate";
import LoadingOverlay from "@insite/mobius/LoadingOverlay";
import ThemeProvider from "@insite/mobius/ThemeProvider";
import BrandStyles from "@insite/shell/BrandStyles";
import { CmsTranslationLoader } from "@insite/shell/Components/CmsTranslationLoader";
import * as LayoutModule from "@insite/shell/Components/Layout";
import ConfirmationProvider from "@insite/shell/Components/Modals/ConfirmationProvider";
import { AdminContextProvider } from "@insite/shell/Components/Shell/AdminContext";
import { trackUserEvents } from "@insite/shell/Services/AccessTokenService";
import { setReduxDispatcher } from "@insite/shell/Services/ServiceBase";
import shellTheme from "@insite/shell/ShellTheme";
import { parseAdminTokenFromLocalStorage } from "@insite/shell/Store/BearerToken";
import { configureStore } from "@insite/shell/Store/ConfigureStore";
import { clearCookiesAndStorage } from "@insite/shell/Store/ShellContext/ShellContextReducer";
import ShellState from "@insite/shell/Store/ShellState";
import * as React from "react";
import { createRoot, hydrateRoot, Root } from "react-dom/client";
import { Provider } from "react-redux";
import { unstable_HistoryRouter as HistoryRouter } from "react-router";
import { css } from "styled-components";

const pages = require.context("../../client-framework/src/Internal/Pages", true, /\.tsx$/);
const onHotPageReplace = addPagesFromContext(pages);

const widgets = require.context("../../client-framework/src/Internal/Widgets", true, /\.tsx$/);
const onHotWidgetReplace = addWidgetsFromContext(widgets);

let Layout = LayoutModule.default;
let theme = shellTheme;

// Get the application-wide store instance, prepopulating with state from the server where available.
const initialState = (window as any).initialReduxState as ShellState;
const { store, history } = configureStore(initialState);
const container = document.getElementById("react-app") as Element;

const loadingCss = css`
    display: block;
    height: 100vh;
`;

function renderApp(root: Root = createRoot(container)) {
    // This code starts up the React app when it runs in a browser. It sets up the routing configuration
    // and injects the app into a DOM element.
    const token = parseAdminTokenFromLocalStorage();
    let shell: JSX.Element;
    if (!token) {
        clearCookiesAndStorage();
        window.location.href = `/admin/signin?returnUrl=${encodeURIComponent(window.location.pathname)}`;
        shell = <LoadingOverlay loading css={loadingCss} />;
    } else {
        trackUserEvents(store.dispatch);
        shell = (
            <Provider store={store}>
                {/* ISC-25343 redux-first-history + the unstable history router + 'as any'
                was the only way I could figure out to get v7 react router to play nicely with redux */}
                <HistoryRouter history={history as any}>
                    <AdminContextProvider>
                        <CmsTranslationLoader>
                            <ConfirmationProvider>
                                <Layout />
                            </ConfirmationProvider>
                        </CmsTranslationLoader>
                    </AdminContextProvider>
                </HistoryRouter>
            </Provider>
        );
    }

    setReduxDispatcher(store.dispatch);

    root.render(
        <ThemeProvider theme={theme} createGlobalStyle={true} createChildGlobals={false} translate={translate}>
            <BrandStyles />
            {shell}
        </ThemeProvider>,
    );
}

renderApp(initialState ? hydrateRoot(container, <></>) : createRoot(container));

if (module.hot) {
    module.hot.accept(pages.id.toString(), () =>
        onHotPageReplace(require.context("../../client-framework/src/Internal/Pages", true, /\.tsx$/)),
    );

    module.hot.accept(widgets.id.toString(), () =>
        onHotWidgetReplace(require.context("../../client-framework/src/Internal/Widgets", true, /\.tsx$/)),
    );

    module.hot.accept("@insite/shell/Components/Layout", () => {
        // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports
        Layout = require<typeof LayoutModule>("@insite/shell/Components/Layout").default;
        renderApp();
    });

    module.hot.accept("@insite/shell/ShellTheme", () => {
        // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports
        theme = require("@insite/shell/ShellTheme").shellTheme;
        renderApp();
    });
}
