import ReactDOM from "react-dom/client";
import "config/i18n"; // Initialize i18n early, before any component renders

import StateManager from "./StateManager";
import ErrorBoundary from "modules/common/global/ErrorBoundary";
import { useMtsState } from "states/MtsState";
import { writeLoginError } from "utils/loginError";

// MSAL Imports
import { MsalProvider, useMsal } from "@azure/msal-react";
import {
  AuthenticationResult,
  createStandardPublicClientApplication,
  EventMessage,
  EventType,
  InteractionStatus
} from "@azure/msal-browser";
import { msalConfig } from "config/msal/authConfig";
import { MsalLoading } from "config/msal/msalComponents";

import "./index.css";
import { ENV_TEST } from "utils/constants";
import { installConsoleErrorRingBuffer } from "modules/common/global/Feedback/diagnostics";

installConsoleErrorRingBuffer();

// https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/6500
export const msalPublicClientApp = await createStandardPublicClientApplication(msalConfig);

// Track the signed-in account explicitly. MsalAuthenticationTemplate doesn't
// set the active account on redirect-flow completion, so without this
// `getActiveAccount()` would always return null and we'd fall back to
// `getAllAccounts()[0]` (stale after account switch).
msalPublicClientApp.addEventCallback((event: EventMessage) => {
  if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) {
    const account = (event.payload as AuthenticationResult).account;
    if (account) {
      msalPublicClientApp.setActiveAccount(account);

      // B2C duplicate cleanup. Re-driving login with prompt=login (and some
      // policy-version migrations) can mint a fresh AccountInfo entry for
      // the same B2C user, leaving stale duplicates in localStorage that
      // surface as ghost rows in the account switcher. Walk the cache and
      // drop any non-active entry that shares the new active account's
      // username (B2C usernames are the canonical identifier).
      try {
        const targetUsername = account.username?.toLowerCase();
        if (targetUsername) {
          const stale = msalPublicClientApp
            .getAllAccounts()
            .filter(
              (a) =>
                a.homeAccountId !== account.homeAccountId &&
                a.username?.toLowerCase() === targetUsername
            );
          for (const dup of stale) {
            // Fire and forget — clearCache is idempotent and a failure here
            // should not block the login flow.
            void msalPublicClientApp.clearCache({ account: dup });
          }
        }
      } catch {
        // Never let cleanup throw past the event callback.
      }

      // "Add account" path: the user was already operating under a
      // different account when they kicked off this login. Wipe the
      // persisted MtsState (userId/email/roles/seller/reseller/flags)
      // so App.tsx's bootstrap picks defaults for the newly-active
      // account rather than inheriting the previous account's
      // operator context. resetState() sets isUserLoggedIn=false →
      // the "first-time" branch of the bootstrap runs.
      let pendingActivation = false;
      try {
        pendingActivation =
          sessionStorage.getItem("mts-pending-account-activation") === "1";
        if (pendingActivation) {
          sessionStorage.removeItem("mts-pending-account-activation");
        }
      } catch {
        // sessionStorage unavailable.
      }
      if (pendingActivation) {
        try {
          useMtsState.getState().resetState();
        } catch {
          // Defensive: never let a state-reset failure block login.
        }
        // Flag for App.tsx bootstrap: it should land the user on "/" with
        // no seller pre-selected. Auto-picking sellers[0] would route the
        // user into a tenant they did not just intentionally choose, and
        // any pre-login URL with seller-scoped IDs would 404/403 against
        // the new account.
        try {
          sessionStorage.setItem("mts-fresh-account-landing", "1");
        } catch {
          // sessionStorage unavailable. App will fall back to the normal
          // first-time bootstrap behaviour.
        }
      }
    }
  }
  if (
    event.eventType === EventType.LOGIN_FAILURE ||
    event.eventType === EventType.ACQUIRE_TOKEN_FAILURE
  ) {
    // installConsoleErrorRingBuffer patches console.error → diagnostics for
    // the in-app feedback / support flow.
    console.error(`MSAL ${event.eventType}`, event.error);
    // Use the runtime event-type string so we don't depend on a TS-typed
    // `LOGIN_FAILURE` member on the `EventType` constant (the runtime enum
    // exposes it, but the typings on this MSAL version do not).
    const code = String(event.eventType).toLowerCase().includes("login")
      ? "b2c_login_failure"
      : "b2c_token_failure";
    writeLoginError(code, event.error?.message ?? String(event.error ?? ""));
  }
});

if (!msalPublicClientApp.getActiveAccount()) {
  const fallback = msalPublicClientApp.getAllAccounts()[0];
  if (fallback) msalPublicClientApp.setActiveAccount(fallback);
}

export const buildLogoutRequest = () => ({
  account:
    msalPublicClientApp.getActiveAccount() ?? msalPublicClientApp.getAllAccounts()[0],
  mainWindowRedirectUri: "/"
});

export const loginRequest = {
  scopes: [import.meta.env.VITE_B2C_SCOPES!]
};

// MSAL interaction gate. Show MsalLoading while MSAL itself is busy
// (Startup, HandleRedirect, Logout); once settled, always mount
// StateManager. The unauth landing (HomePage) lives inside the
// authenticated shell as a route-time decision in App.tsx — that way
// the same Navbar / Router / QueryClientProvider chain is in play in
// both states.
const AuthGate = () => {
  const { inProgress } = useMsal();
  const isBooting =
    inProgress === InteractionStatus.Startup ||
    inProgress === InteractionStatus.HandleRedirect ||
    inProgress === InteractionStatus.Logout;
  if (isBooting) return <MsalLoading />;
  return <StateManager />;
};

const container = document.getElementById("root") as HTMLElement;
const root: ReactDOM.Root = (globalThis as any).__reactRoot ?? ReactDOM.createRoot(container);
(globalThis as any).__reactRoot = root;
(globalThis as { __setStartupProgress?: (pct: number) => void }).__setStartupProgress?.(30);

root.render(
  <div className="h-full w-full">
    <ErrorBoundary>
      {import.meta.env.VITE_ENV === ENV_TEST && <StateManager />}
      {import.meta.env.VITE_ENV !== ENV_TEST && (
        <MsalProvider instance={msalPublicClientApp}>
          <AuthGate />
        </MsalProvider>
      )}
    </ErrorBoundary>
  </div>
);
