"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { AdminDialog } from "@/components/ui/admin-dialog";

interface Props {
  /** Arm the guard — true once the form has unsaved changes. */
  enabled: boolean;
  /** Persist the in-progress PO as a draft. Should navigate away on success. */
  onSaveDraft: () => void;
  /** True while the draft save is in flight (drives the button label/disable). */
  saving: boolean;
}

// Warns the user before they leave a PO form with unsaved changes (issue #18).
// Two paths are covered:
//   • Hard navigations (refresh, tab close, external links) → the browser's own
//     "Leave site?" prompt (browsers can't render custom buttons here, so the
//     save-as-draft option isn't offered on this path).
//   • In-app navigations (sidebar / header / any internal <a>) → intercepted and
//     replaced with our own modal offering Save as draft / Discard / Stay.
export function UnsavedChangesGuard({ enabled, onSaveDraft, saving }: Props) {
  const router = useRouter();
  const [pendingHref, setPendingHref] = useState<string | null>(null);
  // Listeners are attached once; read `enabled` through a ref so they always see
  // the latest value without re-binding on every keystroke.
  const enabledRef = useRef(enabled);
  enabledRef.current = enabled;

  useEffect(() => {
    function onBeforeUnload(e: BeforeUnloadEvent) {
      if (!enabledRef.current) return;
      e.preventDefault();
      e.returnValue = "";
    }
    window.addEventListener("beforeunload", onBeforeUnload);
    return () => window.removeEventListener("beforeunload", onBeforeUnload);
  }, []);

  useEffect(() => {
    function onClick(e: MouseEvent) {
      if (!enabledRef.current || e.defaultPrevented) return;
      // Ignore non-primary clicks and modifier-clicks (new tab / download etc.).
      if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      const anchor = (e.target as HTMLElement | null)?.closest("a");
      const href = anchor?.getAttribute("href");
      if (!anchor || !href || href.startsWith("#")) return;
      if (anchor.hasAttribute("download")) return;
      if (anchor.target && anchor.target !== "_self") return;

      const url = new URL(href, window.location.href);
      // External origin → let the browser's beforeunload prompt handle it.
      if (url.origin !== window.location.origin) return;
      // Same page (e.g. a no-op link) → nothing to guard.
      if (url.pathname === window.location.pathname && url.search === window.location.search) return;

      e.preventDefault();
      e.stopPropagation();
      setPendingHref(url.pathname + url.search + url.hash);
    }
    // Capture phase so we run before Next's <Link> click handler.
    document.addEventListener("click", onClick, true);
    return () => document.removeEventListener("click", onClick, true);
  }, []);

  const discard = useCallback(() => {
    const href = pendingHref;
    setPendingHref(null);
    enabledRef.current = false; // let this navigation through
    if (href) router.push(href);
  }, [pendingHref, router]);

  const stay = useCallback(() => {
    if (saving) return;
    setPendingHref(null);
  }, [saving]);

  function saveDraft() {
    // Close the prompt so any inline save error is visible; the save action
    // navigates to the PO on success.
    setPendingHref(null);
    onSaveDraft();
  }

  return (
    <AdminDialog title="Unsaved changes" open={pendingHref !== null} onClose={stay}>
      <div className="space-y-4">
        <p className="text-sm text-neutral-600">
          You have unsaved changes on this purchase order. Save it as a draft before leaving, or discard your changes?
        </p>
        <div className="flex flex-col gap-2 sm:flex-row sm:justify-end">
          <button
            type="button"
            onClick={stay}
            disabled={saving}
            className="rounded-lg border border-neutral-300 bg-white px-4 py-2 text-sm font-medium text-neutral-700 hover:bg-neutral-50 disabled:opacity-60 sm:order-1"
          >
            Stay on page
          </button>
          <button
            type="button"
            onClick={discard}
            disabled={saving}
            className="rounded-lg border border-danger-200 bg-white px-4 py-2 text-sm font-medium text-danger-700 hover:bg-danger-50 disabled:opacity-60 sm:order-2"
          >
            Discard changes
          </button>
          <button
            type="button"
            onClick={saveDraft}
            disabled={saving}
            className="rounded-lg bg-primary-600 px-4 py-2 text-sm font-semibold text-white hover:bg-primary-700 disabled:opacity-60 transition-colors sm:order-3"
          >
            {saving ? "Saving…" : "Save as draft"}
          </button>
        </div>
      </div>
    </AdminDialog>
  );
}
