import { useCallback, useEffect, useState } from "react";

/**
 * Read the current `?claim=…` query param off `window.location.search`.
 * Returns `null` when the param is absent or empty.
 *
 * `URLSearchParams` is the standard, locale-free way to parse query
 * strings in the browser. Using it (rather than hand-rolled string
 * slicing) means we correctly handle multiple params and percent-encoded
 * characters in claim IDs without surprises.
 */
function readClaimId(): string | null {
  const params = new URLSearchParams(window.location.search);
  // `URLSearchParams.get` returns `""` for `?claim=` (param present but
  // empty) — we normalize that to `null` so the "absent" and "empty"
  // cases are indistinguishable to consumers, matching the JSDoc.
  const value = params.get("claim");
  return value === "" ? null : value;
}

/**
 * Build the URL we want to push/replace into history.
 *
 * - `claimId === null`  →  drop the `?claim=` param, preserving any
 *   other params (e.g. `?foo=bar` stays).
 * - `claimId !== null`  →  set the param to the new id, also preserving
 *   any other params.
 *
 * We return `pathname + search + hash` (a relative URL) rather than the
 * full href — `history.pushState` accepts a relative URL and rewriting
 * only the relative form keeps the document's origin stable. `hash` is
 * appended so a `#section` anchor survives navigation, matching what
 * the browser would do natively.
 */
function buildUrl(claimId: string | null): string {
  const url = new URL(window.location.href);
  if (claimId === null) {
    url.searchParams.delete("claim");
  } else {
    url.searchParams.set("claim", claimId);
  }
  return url.pathname + url.search + url.hash;
}

/**
 * Per-claim detail drawer URL state (SP4).
 *
 * Reads `?claim=` from the URL on mount and keeps the value in sync with
 * history as the drawer is opened, navigated (j/k), and closed. The
 * drawer parent uses this hook as the single source of truth for "is a
 * claim open and which one" — the URL is the durable record so that
 * deep links (`/claims?claim=CLM-1`) restore the drawer state on reload.
 *
 *   - `claimId`: the id parsed from the URL (or `null` when the param
 *     is absent). React state so consumers re-render on changes.
 *   - `open(id)`: pushes a NEW history entry with `?claim={id}` — so the
 *     browser Back button returns to the previous page (e.g. the claims
 *     list) and not just to the previously-open claim.
 *   - `setClaimId(id)`: REPLACES the current history entry — used by the
 *     j/k nav handler so j/k moves through the list without polluting
 *     history with one entry per keystroke.
 *   - `close()`: pushes a NEW entry that strips the param, so Back from
 *     the closed drawer returns to whatever page the user was on before
 *     opening the drawer.
 *
 * The hook subscribes to `popstate` so that browser Back/Forward
 * (which fire popstate rather than our own pushState) propagate into
 * the React state. Without this, hitting Back would change the URL but
 * leave the drawer open on the stale id.
 *
 * Implementation note: this is a single-operator local-only tool, so we
 * call `history.pushState` / `replaceState` directly without try/catch
 * wrappers — the only way they throw in modern browsers is when the URL
 * is malformed, which we control.
 */
export function useDrawerUrlState(): {
  claimId: string | null;
  open: (id: string) => void;
  close: () => void;
  setClaimId: (id: string) => void;
} {
  const [claimId, setClaimIdState] = useState<string | null>(() => readClaimId());

  const open = useCallback((id: string) => {
    window.history.pushState(null, "", buildUrl(id));
    setClaimIdState(id);
  }, []);

  const setClaimId = useCallback((id: string) => {
    window.history.replaceState(null, "", buildUrl(id));
    setClaimIdState(id);
  }, []);

  const close = useCallback(() => {
    window.history.pushState(null, "", buildUrl(null));
    setClaimIdState(null);
  }, []);

  useEffect(() => {
    const onPopState = () => {
      setClaimIdState(readClaimId());
    };
    window.addEventListener("popstate", onPopState);
    return () => window.removeEventListener("popstate", onPopState);
  }, []);

  return { claimId, open, close, setClaimId };
}