"use client";

import { useEffect, useState, createContext, useContext, useCallback } from "react";
import { AlertTriangle, HelpCircle } from "lucide-react";
import clsx from "clsx";

type Ask = {
  title: string;
  body?: string;
  confirmLabel?: string;
  danger?: boolean;
};

type Pending = Ask & { resolve: (ok: boolean) => void };

const Ctx = createContext<(ask: Ask) => Promise<boolean>>(async () => false);

/**
 * The app's own confirmation, in place of window.confirm.
 *
 * The browser dialog blocks the whole tab and looks nothing like the rest of
 * the site, which is jarring right at the moment someone is about to delete
 * something or spend money.
 */
export function ConfirmProvider({ children }: { children: React.ReactNode }) {
  const [pending, setPending] = useState<Pending | null>(null);

  const ask = useCallback(
    (question: Ask) =>
      new Promise<boolean>((resolve) => setPending({ ...question, resolve })),
    []
  );

  const answer = useCallback(
    (ok: boolean) => {
      pending?.resolve(ok);
      setPending(null);
    },
    [pending]
  );

  // Escape cancels, as people expect from a dialog.
  useEffect(() => {
    if (!pending) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") answer(false);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [pending, answer]);

  return (
    <Ctx.Provider value={ask}>
      {children}

      {pending && (
        <div className="cfd-back" onClick={() => answer(false)}>
          {/* cfd-, not cf-: .cf-card is also a crowdfunding card, and the
              later rule was silently flattening this dialog. */}
          <div
            className="cfd-card"
            role="dialog"
            aria-modal="true"
            onClick={(e) => e.stopPropagation()}
          >
            <span className={clsx("cfd-icon", pending.danger && "danger")}>
              {pending.danger ? <AlertTriangle size={22} /> : <HelpCircle size={22} />}
            </span>

            <h3>{pending.title}</h3>
            {pending.body && <p>{pending.body}</p>}

            <div className="cfd-actions">
              <button onClick={() => answer(false)} className="cfd-cancel">
                Cancel
              </button>
              <button
                onClick={() => answer(true)}
                className={clsx("cfd-go", pending.danger && "danger")}
                autoFocus
              >
                {pending.confirmLabel ?? "Confirm"}
              </button>
            </div>
          </div>
        </div>
      )}
    </Ctx.Provider>
  );
}

/** Asks the person to confirm, resolving true when they agree. */
export const useConfirm = () => useContext(Ctx);
