import { useEffect, useRef } from 'react';
import { useLiveQuery } from 'dexie-react-hooks';
import { db } from '@/lib/db/db';
import { cloudUsername, pushBackup } from '@/lib/cloud/client';
import { useConnectivityStore } from '@/stores/connectivityStore';
import { useDebouncedCallback } from '@/lib/useDebouncedCallback';

/**
 * Autosave to the cloud while signed in: whenever durable data changes, debounce
 * a full backup push. A fingerprint of (id:updatedAt) over the durable tables is
 * watched via liveQuery, so it reacts to edits, adds, and deletes alike. High-churn
 * tables (dice rolls, the session recap) are excluded so a roll doesn't trigger a
 * save. No-op when signed out. Mounted once in the app shell.
 */
export function useCloudAutosave(): void {
  const fingerprint = useLiveQuery(async () => {
    const stamp = async (rows: Promise<Array<{ id?: string; campaignId?: string; updatedAt?: string }>>) =>
      (await rows).map((r) => `${r.id ?? r.campaignId ?? ''}:${r.updatedAt ?? ''}`).join(',');
    const [c, ch, e, n, np, q, m, h, cal] = await Promise.all([
      stamp(db.campaigns.toArray()),
      stamp(db.characters.toArray()),
      stamp(db.encounters.toArray()),
      stamp(db.notes.toArray()),
      stamp(db.npcs.toArray()),
      stamp(db.quests.toArray()),
      stamp(db.maps.toArray()),
      stamp(db.homebrew.toArray()),
      stamp(db.calendars.toArray()),
    ]);
    return [c, ch, e, n, np, q, m, h, cal].join('|');
  }, [], undefined);

  const save = useDebouncedCallback(() => {
    if (!cloudUsername()) return;
    const conn = useConnectivityStore.getState();
    conn.setCloudSync('saving');
    void pushBackup()
      .then(() => useConnectivityStore.getState().setCloudSync('saved'))
      .catch(() => useConnectivityStore.getState().setCloudSync('error')); // offline / transient — next change retries
  }, 8000);

  // Skip the initial load; only push once data actually changes after mount.
  const prev = useRef<string | undefined>(undefined);
  useEffect(() => {
    if (fingerprint === undefined) return;
    if (prev.current === undefined) { prev.current = fingerprint; return; }
    if (prev.current !== fingerprint) { prev.current = fingerprint; save(); }
  }, [fingerprint, save]);
}
