import { trpc } from "@/lib/trpc";
import { UNAUTHED_ERR_MSG } from '@shared/const';
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink, TRPCClientError } from "@trpc/client";
import { createRoot } from "react-dom/client";
import superjson from "superjson";
import App from "./App";
import { getLoginUrl } from "./const";
import "./index.css";

const queryClient = new QueryClient();
const ASSET_REFRESH_KEY = "asset-recovery-reloaded";

const redirectToLoginIfUnauthorized = (error: unknown) => {
  if (!(error instanceof TRPCClientError)) return;
  if (typeof window === "undefined") return;

  const isUnauthorized = error.message === UNAUTHED_ERR_MSG;

  if (!isUnauthorized) return;

  window.location.href = getLoginUrl();
};

function reloadForStaleAsset(reason: string) {
  if (typeof window === "undefined") return;

  const alreadyReloaded = window.sessionStorage.getItem(ASSET_REFRESH_KEY) === "1";
  if (alreadyReloaded) {
    console.error("[Asset Recovery] stale asset still failing after reload", reason);
    return;
  }

  window.sessionStorage.setItem(ASSET_REFRESH_KEY, "1");
  console.warn("[Asset Recovery] reloading page due to stale asset failure:", reason);
  window.location.reload();
}

function clearAssetRecoveryFlag() {
  if (typeof window === "undefined") return;
  window.sessionStorage.removeItem(ASSET_REFRESH_KEY);
}

if (typeof window !== "undefined") {
  window.addEventListener("load", () => {
    clearAssetRecoveryFlag();
  }, { once: true });

  window.addEventListener("vite:preloadError", (event) => {
    const customEvent = event as Event & { payload?: unknown; preventDefault: () => void };
    customEvent.preventDefault();
    reloadForStaleAsset(String(customEvent.payload ?? "vite preload error"));
  });

  window.addEventListener("error", (event) => {
    const target = event.target;
    if (!(target instanceof HTMLLinkElement || target instanceof HTMLScriptElement)) {
      return;
    }

    const assetUrl = target instanceof HTMLLinkElement ? target.href : target.src;
    if (assetUrl.includes("/assets/")) {
      reloadForStaleAsset(assetUrl);
    }
  }, true);

  window.addEventListener("unhandledrejection", (event) => {
    const reason = event.reason instanceof Error ? event.reason.message : String(event.reason ?? "");
    if (
      reason.includes("Failed to fetch dynamically imported module") ||
      reason.includes("Importing a module script failed") ||
      reason.includes("Unable to preload CSS")
    ) {
      reloadForStaleAsset(reason);
    }
  });
}

queryClient.getQueryCache().subscribe(event => {
  if (event.type === "updated" && event.action.type === "error") {
    const error = event.query.state.error;
    redirectToLoginIfUnauthorized(error);
    console.error("[API Query Error]", error);
  }
});

queryClient.getMutationCache().subscribe(event => {
  if (event.type === "updated" && event.action.type === "error") {
    const error = event.mutation.state.error;
    redirectToLoginIfUnauthorized(error);
    console.error("[API Mutation Error]", error);
  }
});

const trpcClient = trpc.createClient({
  links: [
    httpBatchLink({
      url: "/api/trpc",
      transformer: superjson,
      fetch(input, init) {
        return globalThis.fetch(input, {
          ...(init ?? {}),
          credentials: "include",
        });
      },
    }),
  ],
});

const analyticsEndpoint = import.meta.env.VITE_ANALYTICS_ENDPOINT;
const analyticsWebsiteId = import.meta.env.VITE_ANALYTICS_WEBSITE_ID;

if (analyticsEndpoint && analyticsWebsiteId && typeof document !== "undefined") {
  const script = document.createElement("script");
  script.defer = true;
  script.src = `${analyticsEndpoint.replace(/\/$/, "")}/umami`;
  script.dataset.websiteId = analyticsWebsiteId;
  document.head.appendChild(script);
}

createRoot(document.getElementById("root")!).render(
  <trpc.Provider client={trpcClient} queryClient={queryClient}>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </trpc.Provider>
);
