import { useEffect, useRef } from "react";
import type { UseFormReturn } from "react-hook-form";
import type { BookingFormInputValues, BookingFormValues } from "./schema";

type BookingForm = UseFormReturn<
  BookingFormInputValues,
  any,
  BookingFormValues
>;

const STORAGE_KEY = "edr.freight.bookingDraft.v1";
// Debounce writes so we don't hit localStorage on every keystroke.
const WRITE_DELAY_MS = 400;

interface BookingDraftSnapshot {
  step: number;
  values: Partial<BookingFormInputValues>;
  savedAt: number;
}

/**
 * Uploaded files can't be serialized to localStorage, so the documents map is
 * stripped before persisting. The customer re-attaches files when they resume —
 * everything else (operation, route, cargo, etc.) survives a refresh.
 */
function stripUnserializable(
  values: BookingFormInputValues,
): Partial<BookingFormInputValues> {
  const { documents: _documents, ...rest } = values;
  return rest;
}

function readDraft(): BookingDraftSnapshot | null {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw) as BookingDraftSnapshot;
    if (!parsed || typeof parsed !== "object" || !parsed.values) return null;
    return parsed;
  } catch {
    // Corrupt or unavailable storage — treat as no draft.
    return null;
  }
}

export function clearBookingDraft(): void {
  try {
    localStorage.removeItem(STORAGE_KEY);
  } catch {
    // Ignore storage errors (private mode, quota, etc.).
  }
}

/**
 * Persists the in-progress booking wizard to localStorage so a refresh (or
 * accidental navigation) doesn't lose the customer's work, and restores it on
 * the next visit.
 *
 * `fresh` is set by the explicit "New Booking" entry points (they navigate with
 * `state: { fresh: true }`). A plain refresh has no such state, so:
 *   - fresh === true  → discard any saved draft and start clean.
 *   - fresh !== true  → restore the saved draft and resume where they left off.
 *
 * Returns `clearDraft` so the page can wipe the draft once the booking is
 * actually submitted.
 */
export function useBookingDraft({
  form,
  step,
  setStep,
  fresh,
}: {
  form: BookingForm;
  step: number;
  setStep: (step: number) => void;
  fresh: boolean;
}): { clearDraft: () => void } {
  // Restore (or clear) exactly once on mount.
  const restoredRef = useRef(false);
  useEffect(() => {
    if (restoredRef.current) return;
    restoredRef.current = true;

    if (fresh) {
      clearBookingDraft();
      return;
    }

    const draft = readDraft();
    if (!draft) return;

    // Merge over current defaults so any new schema fields keep their defaults.
    form.reset(
      { ...form.getValues(), ...draft.values },
      { keepDefaultValues: true },
    );
    if (typeof draft.step === "number") setStep(draft.step);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Persist on every form change (debounced) and whenever the step changes.
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const stepRef = useRef(step);
  stepRef.current = step;

  const write = () => {
    try {
      const snapshot: BookingDraftSnapshot = {
        step: stepRef.current,
        values: stripUnserializable(form.getValues()),
        savedAt: Date.now(),
      };
      localStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot));
    } catch {
      // Ignore storage errors (private mode, quota, etc.).
    }
  };

  useEffect(() => {
    // Don't persist until the initial restore/clear has run.
    if (!restoredRef.current) return;
    const sub = form.watch(() => {
      if (timerRef.current) clearTimeout(timerRef.current);
      timerRef.current = setTimeout(write, WRITE_DELAY_MS);
    });
    return () => {
      sub.unsubscribe();
      if (timerRef.current) clearTimeout(timerRef.current);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [form]);

  // Step changes are immediate (no debounce) so a refresh lands on the right step.
  useEffect(() => {
    if (!restoredRef.current) return;
    write();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [step]);

  return { clearDraft: clearBookingDraft };
}
