import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
import type { EngineSnapshot, IEngine } from "@newvexa/workify";
import { createOrderEngine } from "../vanilla";

/** Pour le SSR, fournir le snapshot initial partagé avec l'hydratation. */
export function useWorkflow(
  engine: IEngine,
  getServerSnapshot?: () => EngineSnapshot,
): EngineSnapshot {
  const subscribe = useCallback((listener: () => void) => engine.subscribe(listener), [engine]);
  const getSnapshot = useCallback(() => engine.getSnapshot(), [engine]);
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot ?? getSnapshot);
}

/** Exemple client : créer le moteur une seule fois, lancer sur une action utilisateur. */
export function WorkflowExample() {
  const [engine] = useState(() => createOrderEngine());
  const snapshot = useWorkflow(engine);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const active = useRef<AbortController | null>(null);

  useEffect(() => {
    const stop = engine.onEvent((event) => {
      if (event.type === "node.changed" && event.state.status === "failed") {
        console.error(event.nodeId, event.state.error?.message);
      }
    });
    return () => {
      stop();
      active.current?.abort();
      // Le moteur attend encore les tâches en vol ; abort n'est pas un arrêt forcé.
    };
  }, [engine]);

  async function run(total: number) {
    // Le ref ferme aussi la fenêtre précédant le prochain rendu.
    if (active.current) return;
    const controller = new AbortController();
    active.current = controller;
    setBusy(true);
    setError(null);
    try {
      await engine.run({ orderId: "REACT-001", total }, { signal: controller.signal });
    } catch (cause: unknown) {
      setError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      active.current = null;
      setBusy(false);
    }
  }

  return (
    <section>
      <h2>Commandes</h2>
      <p>État : {snapshot.status}</p>
      <p>Prioritaire : {snapshot.nodes.priority?.status ?? "pending"}</p>
      <p>Standard : {snapshot.nodes.standard?.status ?? "pending"}</p>
      <button disabled={busy} onClick={() => void run(1500)}>Commande de 1 500</button>
      <button disabled={busy} onClick={() => void run(250)}>Commande de 250</button>
      <button disabled={!busy} onClick={() => active.current?.abort()}>Annuler</button>
      {error && <p role="alert">{error}</p>}
    </section>
  );
}
