/*
 * QQQ - Low-code Application Framework for Engineers.
 * Copyright (C) 2021-2022.  Kingsrook, LLC
 * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
 * contact@kingsrook.com
 * https://github.com/Kingsrook/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

import {Auth0Provider} from "@auth0/auth0-react";
import {QAuthenticationMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAuthenticationMetaData";
import React from "react";
import {createRoot} from "react-dom/client";
import {BrowserRouter, useNavigate, useSearchParams} from "react-router-dom";
import App from "App";
import "qqq/styles/qqq-override-styles.css";
import "qqq/styles/globals.scss";
import "qqq/styles/raycast.scss";
import HandleAuthorizationError from "HandleAuthorizationError";
import ProtectedRoute from "qqq/authorization/auth0/ProtectedRoute";
import {MaterialUIControllerProvider} from "qqq/context";
import Client from "qqq/utils/qqq/Client";

const qController = Client.getInstance();

if(document.location.search && document.location.search.indexOf("clearAuthenticationMetaDataLocalStorage") > -1)
{
   qController.clearAuthenticationMetaDataLocalStorage()
}

const authenticationMetaDataPromise: Promise<QAuthenticationMetaData> = qController.getAuthenticationMetaData()

authenticationMetaDataPromise.then((authenticationMetaData) =>
{
   // @ts-ignore
   function Auth0ProviderWithRedirectCallback({children, ...props})
   {
      const navigate = useNavigate();
      const [searchParams] = useSearchParams();

      // @ts-ignore
      const onRedirectCallback = (appState) =>
      {
         navigate((appState && appState.returnTo) || window.location.pathname);
      };
      if (searchParams.get("error"))
      {
         return (
            // @ts-ignore
            <Auth0Provider {...props}>
               <HandleAuthorizationError errorMessage={searchParams.get("error_description")} />
            </Auth0Provider>
         );
      }
      else
      {
         return (
            // @ts-ignore
            <Auth0Provider onRedirectCallback={onRedirectCallback} {...props}>
               {children}
            </Auth0Provider>
         );
      }
   }

   const container = document.getElementById("root");
   const root = createRoot(container);

   if (authenticationMetaData.type === "AUTH_0")
   {
      // @ts-ignore
      let domain: string = authenticationMetaData.data.baseUrl;

      // @ts-ignore
      const clientId = authenticationMetaData.data.clientId;

      // @ts-ignore
      const audience = authenticationMetaData.data.audience;

      if(!domain || !clientId)
      {
         root.render(
            <div>Error:  AUTH0 authenticationMetaData is missing domain [{domain}] and/or clientId [{clientId}].</div>
         );
         return;
      }

      if(domain.endsWith("/"))
      {
         /////////////////////////////////////////////////////////////////////////////////////
         // auth0 lib fails if we have a trailing slash.  be a bit more graceful than that. //
         /////////////////////////////////////////////////////////////////////////////////////
         domain = domain.replace(/\/$/, "");
      }

      root.render(
         <BrowserRouter>
            <Auth0ProviderWithRedirectCallback
               domain={domain}
               clientId={clientId}
               audience={audience}
               redirectUri={`${window.location.origin}/`}
            >
               <MaterialUIControllerProvider>
                  <ProtectedRoute component={App} />
               </MaterialUIControllerProvider>
            </Auth0ProviderWithRedirectCallback>
         </BrowserRouter>
      );
   }
   else
   {
      root.render(
         <BrowserRouter>
            <MaterialUIControllerProvider>
               <App />
            </MaterialUIControllerProvider>
         </BrowserRouter>
      );
   }

})
