import { useCallback, useEffect, useRef, useState } from 'react';
import { getCsrfToken } from '@/lib/csrf';
import { isFullyEmpty } from '@/server/schemas/vendor-deal-draft';
import { captureCaught } from '@/lib/observability';
import { fetchWithRefresh } from '@/lib/api/refresh-on-401';

type State = 'idle' | 'saving' | 'saved' | 'error';

const DEBOUNCE_MS = 5000;
const LS_MAX = 100 * 1024;

function lsKey(vendorId: string, draftId: string | null) {
  return `vendor-draft:${vendorId}:${draftId ?? 'new'}`;
}

export function useDraftAutosave(args: {
  vendorId: string;
  initialDraftId: string | null;
  payload: Record<string, unknown>;
  enabled: boolean;
}) {
  const [draftId, setDraftId] = useState<string | null>(args.initialDraftId);
  const [state, setState] = useState<State>('idle');
  const [savedAt, setSavedAt] = useState<Date | null>(null);
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const payloadRef = useRef(args.payload);
  const draftIdRef = useRef(draftId);

  useEffect(() => {
    payloadRef.current = args.payload;
  }, [args.payload]);

  useEffect(() => {
    draftIdRef.current = draftId;
  }, [draftId]);

  const saveNow = useCallback(async () => {
    const p = payloadRef.current;
    if (isFullyEmpty(p)) return;
    setState('saving');
    try {
      const serialized = JSON.stringify(p);
      const currentDraftId = draftIdRef.current;
      if (serialized.length <= LS_MAX) {
        localStorage.setItem(
          lsKey(args.vendorId, currentDraftId),
          JSON.stringify({ payload: p, updatedAt: new Date().toISOString() }),
        );
      }
      const url = currentDraftId
        ? `/api/vendor/deals/drafts/${currentDraftId}`
        : '/api/vendor/deals/drafts';
      const method = currentDraftId ? 'PATCH' : 'POST';
      const res = await fetchWithRefresh(url, {
        method,
        headers: {
          'content-type': 'application/json',
          'x-csrf-token': getCsrfToken(),
        },
        body: serialized,
        credentials: 'same-origin',
      });
      if (res.status === 204) {
        // Server deleted row (fully empty after PATCH) — clear draft state
        localStorage.removeItem(lsKey(args.vendorId, currentDraftId));
        setDraftId(null);
        setState('idle');
        return;
      }
      if (!res.ok) throw new Error(String(res.status));
      const data = (await res.json()) as { draft?: { id?: string } };
      const newId = data.draft?.id;
      if (newId && !currentDraftId) {
        setDraftId(newId);
        const pageUrl = new URL(window.location.href);
        pageUrl.searchParams.set('draftId', newId);
        window.history.replaceState({}, '', pageUrl.toString());
      }
      setSavedAt(new Date());
      setState('saved');
    } catch (err) {
      captureCaught(err, {
        scope: 'features.vendor-add-deal.useDraftAutosave',
        severity: 'warning',
      });
      setState('error');
    }
  }, [args.vendorId]);

  // Debounced save on payload change
  useEffect(() => {
    if (!args.enabled) return;
    if (isFullyEmpty(args.payload)) return;
    if (timer.current) clearTimeout(timer.current);
    timer.current = setTimeout(saveNow, DEBOUNCE_MS);
    return () => {
      if (timer.current) clearTimeout(timer.current);
    };
  }, [args.payload, args.enabled, saveNow]);

  // Save on window blur
  useEffect(() => {
    const onBlur = () => {
      if (args.enabled) void saveNow();
    };
    window.addEventListener('blur', onBlur);
    return () => window.removeEventListener('blur', onBlur);
  }, [args.enabled, saveNow]);

  return { draftId, state, savedAt, saveNow };
}
