"use client";

import { createContext, useContext, useEffect, useState } from "react";

import type { AuthSession } from "@rental/shared";

import { clearStoredSession, readStoredSession, saveStoredSession, sessionSyncEventName } from "../../lib/api";

type SessionContextValue = {
  session: AuthSession | null;
  ready: boolean;
  setSession: (session: AuthSession | null) => void;
};

const SessionContext = createContext<SessionContextValue | undefined>(undefined);

export const SessionProvider = ({ children }: { children: React.ReactNode }) => {
  const [session, setSessionState] = useState<AuthSession | null>(null);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    setSessionState(readStoredSession());
    setReady(true);
  }, []);

  useEffect(() => {
    const syncSessionState = () => {
      setSessionState(readStoredSession());
    };

    window.addEventListener("storage", syncSessionState);
    window.addEventListener(sessionSyncEventName, syncSessionState);

    return () => {
      window.removeEventListener("storage", syncSessionState);
      window.removeEventListener(sessionSyncEventName, syncSessionState);
    };
  }, []);

  useEffect(() => {
    let reloadingForChunkError = false;

    const shouldReloadForChunkError = (message: string) => {
      const normalizedMessage = message.toLowerCase();

      return (
        normalizedMessage.includes("chunkloaderror") ||
        normalizedMessage.includes("loading chunk") ||
        normalizedMessage.includes("failed to fetch dynamically imported module") ||
        normalizedMessage.includes("importing a module script failed")
      );
    };

    const reloadApplication = () => {
      if (reloadingForChunkError || typeof window === "undefined") {
        return;
      }

      reloadingForChunkError = true;
      window.location.reload();
    };

    const handleWindowError = (event: ErrorEvent) => {
      const message = event.message || event.error?.message || "";

      if (shouldReloadForChunkError(message)) {
        reloadApplication();
      }
    };

    const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
      const reason =
        typeof event.reason === "string"
          ? event.reason
          : event.reason instanceof Error
            ? event.reason.message
            : "";

      if (shouldReloadForChunkError(reason)) {
        reloadApplication();
      }
    };

    window.addEventListener("error", handleWindowError);
    window.addEventListener("unhandledrejection", handleUnhandledRejection);

    return () => {
      window.removeEventListener("error", handleWindowError);
      window.removeEventListener("unhandledrejection", handleUnhandledRejection);
    };
  }, []);

  const setSession = (nextSession: AuthSession | null) => {
    setSessionState(nextSession);

    if (nextSession) {
      saveStoredSession(nextSession);
      return;
    }

    clearStoredSession();
  };

  return <SessionContext.Provider value={{ session, ready, setSession }}>{children}</SessionContext.Provider>;
};

export const useSessionContext = () => {
  const context = useContext(SessionContext);

  if (!context) {
    throw new Error("useSessionContext must be used within SessionProvider");
  }

  return context;
};
