import { lazy } from 'react';

/**
 * Checks whether an error is a chunk/module load failure.
 * These happen when the browser tries to fetch a JS chunk that no longer
 * exists on the server (e.g. after a new deployment replaced the hashed files).
 */
const isChunkLoadError = (error: unknown): boolean => {
  if (!(error instanceof Error)) return false;

  const msg = error.message?.toLowerCase() ?? '';

  return (
    // Vite / modern browsers
    msg.includes('failed to fetch dynamically imported module') ||
    // Chrome / Edge
    msg.includes('importing a module script failed') ||
    // Firefox
    msg.includes('error loading dynamically imported module') ||
    // Safari
    msg.includes('failed to load module script') ||
    // Generic network / chunk errors
    msg.includes('loading chunk') ||
    msg.includes('loading css chunk')
  );
};

const SESSION_KEY = 'retry-lazy-refreshed';
const COOLDOWN_MS = 30_000;

/**
 * Wrapper around React.lazy that automatically reloads the page once
 * when a dynamic import fails due to stale chunk hashes (post-deployment).
 *
 * Stores a timestamp instead of a boolean so that a single reload covers
 * ALL stale chunks. Any chunk failure within COOLDOWN_MS of the last
 * reload-retry is treated as a real error (no second reload).
 *
 * Usage:
 *   const MyComponent = lazyRetry(() => import('./MyComponent'));
 *
 * For re-exported / named exports:
 *   const MyComponent = lazyRetry(() =>
 *     import('./barrel').then(m => ({ default: m.MyComponent })),
 *   );
 */
// biome-ignore lint/suspicious/noExplicitAny: must match React.lazy's own ComponentType<any> bound
export const lazyRetry = <T extends React.ComponentType<any>>(
  componentImport: () => Promise<{ default: T }>,
) =>
  lazy(async () => {
    const lastRetry = Number(window.sessionStorage.getItem(SESSION_KEY) || '0');
    const recentlyRetried = Date.now() - lastRetry < COOLDOWN_MS;

    try {
      return await componentImport();
    } catch (error: unknown) {
      if (!recentlyRetried && isChunkLoadError(error)) {
        window.sessionStorage.setItem(SESSION_KEY, String(Date.now()));
        window.location.reload();
        // Never resolves — prevents React from rendering while the browser reloads
        return new Promise(() => undefined);
      }

      throw error;
    }
  });
