'use client';

import { useCallback, useEffect, useRef, useState } from 'react';

/**
 * Generic Auto-Save-Hook mit Debounce + Status-Tracking + Milestone-Snapshots.
 *
 * Verwendung:
 *   const { status, lastSavedAt, flush, snapshot } = useAutoSave({
 *     draftId,
 *     payload: { briefingJson, tiptapJson, strategyJson },
 *     enabled: !!draftId,
 *     debounceMs: 3000,
 *     autoSnapshotMs: 5 * 60_000,
 *   });
 *
 * - `status`        idle/saving/saved/error — fürs UI (AutoSaveIndicator).
 * - `flush()`       erzwingt sofortiges Save (z.B. vor unmount, vor Send).
 * - `snapshot(...)` erzeugt manuell eine Version (Milestone oder benannt).
 */

export type AutoSaveStatus = 'idle' | 'saving' | 'saved' | 'error';

export interface UseAutoSaveOptions<T> {
  draftId: string | null;
  payload: T;
  enabled?: boolean;
  debounceMs?: number;
  /** Wenn > 0: erzeugt nach dem Save eine Auto-Version, falls die letzte Version älter ist als dieser Wert. */
  autoSnapshotMs?: number;
}

export interface SnapshotOptions {
  source?: 'manual' | 'milestone';
  label?: string;
  milestone?: 'generate' | 'render' | 'send';
}

export function useAutoSave<T>(opts: UseAutoSaveOptions<T>) {
  const {
    draftId,
    payload,
    enabled = true,
    debounceMs = 3000,
    autoSnapshotMs = 5 * 60_000,
  } = opts;

  const [status, setStatus] = useState<AutoSaveStatus>('idle');
  const [lastSavedAt, setLastSavedAt] = useState<Date | null>(null);
  const [error, setError] = useState<string | null>(null);

  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastPayloadRef = useRef<string>('');
  const lastAutoSnapshotAtRef = useRef<number>(0);
  // Wir nehmen JSON.stringify als billigen Change-Detector — Briefing/Tiptap-State sind klein genug.
  const serialized = JSON.stringify(payload);

  /** Zentrale Save-Funktion — feuert sofort ohne Debounce. */
  const save = useCallback(async () => {
    if (!draftId) return;
    setStatus('saving');
    setError(null);
    try {
      const res = await fetch(`/api/drafts/${draftId}`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: serialized,
      });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error(data.error ?? `Save failed (${res.status})`);
      }
      const now = Date.now();
      lastPayloadRef.current = serialized;
      setLastSavedAt(new Date(now));
      setStatus('saved');

      // 5min-Heartbeat: erzeuge eine 'auto'-Version falls überfällig
      if (autoSnapshotMs > 0 && now - lastAutoSnapshotAtRef.current >= autoSnapshotMs) {
        lastAutoSnapshotAtRef.current = now;
        await fetch(`/api/drafts/${draftId}/versions`, {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({ source: 'auto' }),
        }).catch(() => { /* swallow — auto-versions sind best-effort */ });
      }
    } catch (e) {
      setStatus('error');
      setError(e instanceof Error ? e.message : 'Save error');
    }
  }, [draftId, serialized, autoSnapshotMs]);

  // Debounce-Trigger bei Payload-Änderung
  useEffect(() => {
    if (!enabled || !draftId) return;
    if (serialized === lastPayloadRef.current) return; // nichts geändert

    if (timerRef.current) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => { void save(); }, debounceMs);

    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, [serialized, enabled, draftId, debounceMs, save]);

  /** Erzwingt sofortiges Save (debounce-bypass). */
  const flush = useCallback(async () => {
    if (timerRef.current) clearTimeout(timerRef.current);
    await save();
  }, [save]);

  /** Erzeugt eine benannte oder Milestone-Version. Wartet vorher auf flush, damit die Version
   *  den allerneuesten Stand reflektiert. */
  const snapshot = useCallback(async (snapOpts: SnapshotOptions = {}) => {
    if (!draftId) return null;
    await flush();
    const res = await fetch(`/api/drafts/${draftId}/versions`, {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({
        source: snapOpts.source ?? (snapOpts.milestone ? 'milestone' : 'manual'),
        label: snapOpts.label,
        milestone: snapOpts.milestone,
      }),
    });
    if (!res.ok) return null;
    const data = await res.json();
    return data.version ?? null;
  }, [draftId, flush]);

  return { status, lastSavedAt, error, flush, snapshot };
}
