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

/**
 * Read the current `?ack=…` 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 ack ids without surprises.
 *
 * Param name is `?ack=` — chosen to mirror the existing `?provider=…`,
 * `?claim=…`, and `?remit=…` drilldown conventions (one-word token,
 * alphabetical brevity, no collision with the existing `Acks` table
 * columns). The id value is treated as a string in the URL so deep
 * links (`/acks?ack=42`) round-trip identically across the app, even
 * though the backend `Ack.id` is a numeric — `AckDrawer` does the
 * `Number()` coercion when calling `api.getAck`.
 */
function readAckId(): string | null {
  const params = new URLSearchParams(window.location.search);
  const value = params.get("ack");
  return value === "" ? null : value;
}

/**
 * Build the URL we want to push/replace into history.
 *
 * - `ackId === null`  →  drop the `?ack=` param, preserving any
 *   other params (e.g. `?page=2&ack=…` keeps `page=2`).
 * - `ackId !== 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.
 */
function buildUrl(ackId: string | null): string {
  const url = new URL(window.location.href);
  if (ackId === null) {
    url.searchParams.delete("ack");
  } else {
    url.searchParams.set("ack", ackId);
  }
  return url.pathname + url.search + url.hash;
}

/**
 * Per-ack detail drawer URL state (AckDrawer).
 *
 * Mirrors `useProviderDrawerUrlState` / `useRemitDrawerUrlState` but
 * for the 999-ACK drawer — reads `?ack=` from the URL on mount and
 * keeps the value in sync with history as the drawer is opened and
 * closed.
 *
 *   - `ackId`: 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 `?ack={id}` — so the
 *     browser Back button returns to the previous page (e.g. the
 *     acks list) and not just to the previously-open ack.
 *   - `setAckId(id)`: REPLACES the current history entry — kept for
 *     symmetry with the other drawer hooks so a future j/k nav
 *     handler doesn't have to special-case ack ids.
 *   - `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.
 */
export function useAckDrawerUrlState(): {
  ackId: string | null;
  open: (id: string) => void;
  close: () => void;
  setAckId: (id: string) => void;
} {
  const [ackId, setAckIdState] = useState<string | null>(() => readAckId());

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

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

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

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

  return { ackId, open, close, setAckId };
}
