import { useEffect, useCallback } from "react";
import { RSC_HMR_EVENT } from "./createReactFetcher.js";
import type { RscHmrData } from "./createReactFetcher.js";
import { env } from "./env.js";

// Mirror of refreshCssLinks in virtualRscHmrPlugin.ts (see comment there).
// data.file is the project-relative path (eg "src/css/9mmc.module.css") and
// the link href is a URL whose pathname ends with the same suffix.
// Falls back to basename matching for edge cases where the project-relative
// form doesn't appear verbatim in the href.
function refreshCssLinks(data: RscHmrData): boolean {
  if (!data || typeof document === "undefined") return false;
  const rel = String(data.file || "").replace(/^[\\/]+/, "");
  if (!rel) return false;
  const basename = rel.split(/[\\/]/).pop();
  const links = document.querySelectorAll('link[rel="stylesheet"]');
  let refreshed = 0;
  links.forEach((link) => {
    const href = link.getAttribute("href");
    if (!href) return;
    let pathname: string;
    try {
      pathname = new URL(href, window.location.origin).pathname;
    } catch {
      pathname = href.split("?")[0] ?? "";
    }
    const matches =
      pathname.endsWith("/" + rel) ||
      pathname.endsWith(rel) ||
      (!!basename && pathname.endsWith("/" + basename));
    if (!matches) return;
    const url = new URL(href, window.location.origin);
    url.searchParams.set("t", String(Date.now()));
    link.setAttribute("href", url.pathname + url.search);
    refreshed++;
  });
  return refreshed > 0;
}

/**
 * React hook for RSC HMR (Hot Module Replacement).
 * 
 * When a server component file changes, this hook calls your `refetch` function
 * to re-fetch the RSC stream. Combined with `startTransition`, this preserves
 * client component state while updating server-rendered content.
 * 
 * @example
 * ```tsx
 * import { useRscHmr } from 'vite-plugin-react-server/utils';
 * 
 * function Shell({ data }) {
 *   const [storeData, setStoreData] = useState(data);
 *   
 *   const refetch = useCallback((url: string) => {
 *     startTransition(() => {
 *       setStoreData(createReactFetcher({ url }));
 *     });
 *   }, []);
 *   
 *   // Refetch RSC stream when server components change
 *   useRscHmr(refetch);
 *   
 *   return <>{use(storeData)}</>;
 * }
 * ```
 * 
 * @param refetch - Function to call when server components change. 
 *   Receives the current pathname. Use `startTransition` inside for smooth updates.
 * @param options - Optional configuration
 */
export function useRscHmr(
  refetch: (url: string) => void,
  options: {
    /** Whether to log HMR events. @default true in dev */
    verbose?: boolean;
    /** Custom filter — return false to skip refetch for specific files */
    filter?: (data: RscHmrData) => boolean;
  } = {}
) {
  const { verbose = env.DEV, filter } = options;

  const handler = useCallback(
    (data: RscHmrData) => {
      if (filter && !filter(data)) return;
      const kind = (data as { kind?: string }).kind;
      if (verbose) {
        console.log('[RSC HMR] Server component updated:', data.file, kind ? `(${kind})` : '');
      }
      if (kind === 'css') {
        refreshCssLinks(data);
      }
      refetch(window.location.pathname);
    },
    [refetch, verbose, filter]
  );

  useEffect(() => {
    if (typeof import.meta.hot === 'undefined') return;

    import.meta.hot.on(RSC_HMR_EVENT, handler);
    
    if (verbose) {
      console.log('[RSC HMR] Listening for server component updates');
    }

    return () => {
      import.meta.hot!.off(RSC_HMR_EVENT, handler);
    };
  }, [handler, verbose]);
}
