"use client";

import { createContext, ReactNode, useCallback, useContext, useEffect, useRef, useState } from "react";
import { SaveIcon } from "./icons";

/**
 * Page-level "save bus": editable sections register a dirty flag + a save handler,
 * and a single floating action button commits everything at once — so a page with
 * many per-row/per-form save buttons collapses to one. Register via useSaveItem().
 */
type Entry = { dirty: boolean; save: () => Promise<void> };
type Bus = { set: (id: string, entry: Entry) => void; remove: (id: string) => void };

const BusContext = createContext<Bus | null>(null);

export function SaveBusProvider({ children }: { children: ReactNode }) {
  const entries = useRef<Map<string, Entry>>(new Map());
  const [dirtyCount, setDirtyCount] = useState(0);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const recompute = useCallback(() => {
    let n = 0;
    entries.current.forEach((e) => {
      if (e.dirty) n++;
    });
    setDirtyCount((prev) => (prev === n ? prev : n));
  }, []);

  const bus = useRef<Bus>({
    set: (id, entry) => {
      entries.current.set(id, entry);
      recompute();
    },
    remove: (id) => {
      entries.current.delete(id);
      recompute();
    },
  }).current;

  const saveAll = useCallback(async () => {
    setSaving(true);
    setError(null);
    try {
      const tasks: Promise<void>[] = [];
      entries.current.forEach((e) => {
        if (e.dirty) tasks.push(e.save());
      });
      await Promise.all(tasks);
      recompute();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setSaving(false);
    }
  }, [recompute]);

  return (
    <BusContext.Provider value={bus}>
      {children}
      {dirtyCount > 0 && (
        <div className="fixed bottom-6 right-6 z-40 flex flex-col items-end gap-2">
          {error && (
            <div className="max-w-xs rounded-md bg-red-600 px-3 py-2 text-xs text-white shadow-lg" role="alert">
              {error}
            </div>
          )}
          <button
            type="button"
            onClick={saveAll}
            disabled={saving}
            className="flex items-center gap-2 rounded-full bg-brand px-5 py-3 text-sm font-semibold text-white shadow-lg transition hover:bg-brand-dark disabled:opacity-60"
          >
            <SaveIcon className="h-5 w-5" />
            {saving ? "Saving…" : `Save ${dirtyCount} change${dirtyCount === 1 ? "" : "s"}`}
          </button>
        </div>
      )}
    </BusContext.Provider>
  );
}

/**
 * Register an editable section with the save bus. `save` MUST be stable
 * (wrap in useCallback) to avoid churn; `dirty` toggles the FAB.
 */
export function useSaveItem(id: string, dirty: boolean, save: () => Promise<void>) {
  const bus = useContext(BusContext);
  useEffect(() => {
    if (!bus) return;
    bus.set(id, { dirty, save });
    return () => bus.remove(id);
  }, [bus, id, dirty, save]);
}
