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

type ContractForm = UseFormReturn<
  ContractFormInputValues,
  any,
  ContractFormValues
>;

const STORAGE_KEY = "edr.freight.contractDraft.v1";
const WRITE_DELAY_MS = 400;

interface ContractDraftSnapshot {
  step: number;
  values: Partial<ContractFormInputValues>;
  savedAt: number;
}

/** Files can't be serialized — strip the documents map before persisting. */
function stripUnserializable(
  values: ContractFormInputValues,
): Partial<ContractFormInputValues> {
  const { documents: _documents, ...rest } = values;
  return rest;
}

function readDraft(): ContractDraftSnapshot | null {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw) as ContractDraftSnapshot;
    if (!parsed || typeof parsed !== "object" || !parsed.values) return null;
    return parsed;
  } catch {
    return null;
  }
}

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

/**
 * Persists the in-progress contract wizard to localStorage so a refresh doesn't
 * lose the customer's work, and restores it on the next visit. Mirrors the
 * booking wizard's `useBookingDraft`.
 */
export function useContractDraft({
  form,
  step,
  setStep,
  fresh,
  enabled = true,
}: {
  form: ContractForm;
  step: number;
  setStep: (step: number) => void;
  fresh: boolean;
  /**
   * When false the draft is neither restored nor persisted — used in edit mode,
   * where the server contract is the source of truth and the localStorage key is
   * shared with the create flow.
   */
  enabled?: boolean;
}): { clearDraft: () => void } {
  const restoredRef = useRef(false);
  useEffect(() => {
    if (!enabled) return;
    if (restoredRef.current) return;
    restoredRef.current = true;

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

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

    form.reset(
      { ...form.getValues(), ...draft.values },
      { keepDefaultValues: true },
    );
    // Clamp to the current step range — older drafts may carry a step id that
    // no longer exists after the wizard was condensed to 4 steps.
    if (typeof draft.step === "number") {
      setStep(Math.min(Math.max(draft.step, 0), 3));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const stepRef = useRef(step);
  stepRef.current = step;

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

  useEffect(() => {
    if (!enabled) return;
    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, enabled]);

  useEffect(() => {
    if (!enabled) return;
    if (!restoredRef.current) return;
    write();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [step]);

  return { clearDraft: clearContractDraft };
}
