import { useCallback, useEffect, useRef, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { toast } from "sonner";
import {
  loadApplicantDraftBundle,
  saveApplicantDraftTab,
  readInitialApplicantCaseId,
  readReportStepDoneFromSession,
  reportDraftLooksComplete,
  REPORT_STEP_SESSION_KEY,
  APPLICANT_CASE_ID_SESSION_KEY,
  CASE_ID_SEARCH_PARAM,
  FRESH_DASHBOARD_SEARCH_PARAM,
  prepareFreshApplicantDashboardNavigation,
} from "@ump/shared";

/**
 * Applicant draft session for `/dashboard`:
 * - **New application** — `?fresh=1` clears storage and shows empty forms until first save (Postgres).
 * - **Resume / review** — `sessionStorage` case id or `?caseId=` loads `GET /api/v1/application-drafts/:caseId`.
 */
export type ApplicantDraftLoadStatus = "idle" | "loading" | "ready" | "error";

export function useApplicantRegistrationState() {
  const [searchParams, setSearchParams] = useSearchParams();

  const [applicationCaseId, setApplicationCaseId] = useState<string>(readInitialApplicantCaseId);
  const [draftTabs, setDraftTabs] = useState<Record<string, Record<string, unknown> | undefined>>({});
  const [reportStepCompleted, setReportStepCompleted] = useState(readReportStepDoneFromSession);
  const [activeApplicantTab, setActiveApplicantTab] = useState("report");
  const [applicantDraftMountKey, setApplicantDraftMountKey] = useState(0);
  const [draftLoadStatus, setDraftLoadStatus] = useState<ApplicantDraftLoadStatus>(() =>
    readInitialApplicantCaseId() ? "loading" : "idle",
  );

  /** After `?caseId=` is consumed, the URL becomes plain `/dashboard` — skip one plain-URL reset so we do not wipe the resumed case. */
  const skipPlainDashboardResetAfterCaseIdUrl = useRef(false);

  /**
   * Plain `/dashboard` (no `?fresh=1`, no `?caseId=`) clears session and starts a new registration.
   * Resume only via `?caseId=...` in the URL — not when `reportStepCompleted` / `draftTabs` change in-session.
   * Dependencies must stay `[searchParams]` only; including draft/report state re-ran this effect after
   * "Tiếp theo" on the report tab and undid the tab change.
   */
  useEffect(() => {
    const isFresh = searchParams.get(FRESH_DASHBOARD_SEARCH_PARAM) === "1";
    const hasCaseIdFromUrl = Boolean(searchParams.get(CASE_ID_SEARCH_PARAM)?.trim());
    if (isFresh || hasCaseIdFromUrl) return;
    if (skipPlainDashboardResetAfterCaseIdUrl.current) {
      skipPlainDashboardResetAfterCaseIdUrl.current = false;
      return;
    }

    prepareFreshApplicantDashboardNavigation();
    setApplicationCaseId("");
    setDraftTabs({});
    setReportStepCompleted(false);
    setActiveApplicantTab("report");
    setDraftLoadStatus("idle");
    setApplicantDraftMountKey((k) => k + 1);
  }, [searchParams]);

  /** `?fresh=1` — empty forms, new draft row on next save (Postgres). */
  useEffect(() => {
    if (searchParams.get(FRESH_DASHBOARD_SEARCH_PARAM) !== "1") return;
    prepareFreshApplicantDashboardNavigation();
    setApplicationCaseId("");
    setDraftTabs({});
    setReportStepCompleted(false);
    setActiveApplicantTab("report");
    setDraftLoadStatus("idle");
    setApplicantDraftMountKey((k) => k + 1);
    setSearchParams(
      (prev) => {
        const next = new URLSearchParams(prev);
        next.delete(FRESH_DASHBOARD_SEARCH_PARAM);
        next.delete(CASE_ID_SEARCH_PARAM);
        return next;
      },
      { replace: true },
    );
  }, [searchParams, setSearchParams]);

  /** `?caseId=` — resume / review in-progress draft from Postgres (after `?fresh` handling). */
  useEffect(() => {
    if (searchParams.get(FRESH_DASHBOARD_SEARCH_PARAM) === "1") return;
    const cid = searchParams.get(CASE_ID_SEARCH_PARAM)?.trim();
    if (!cid) return;
    try {
      sessionStorage.setItem(APPLICANT_CASE_ID_SESSION_KEY, cid);
    } catch {
      /* ignore */
    }
    setApplicationCaseId(cid);
    setApplicantDraftMountKey((k) => k + 1);
    skipPlainDashboardResetAfterCaseIdUrl.current = true;
    setSearchParams(
      (prev) => {
        const next = new URLSearchParams(prev);
        next.delete(CASE_ID_SEARCH_PARAM);
        return next;
      },
      { replace: true },
    );
  }, [searchParams, setSearchParams]);

  /** Load tab bundle from server when case id is set (Postgres-backed drafts). */
  useEffect(() => {
    if (!applicationCaseId) {
      setDraftLoadStatus((s) => (s === "error" ? s : "idle"));
      return;
    }

    let cancelled = false;
    setDraftLoadStatus("loading");

    void loadApplicantDraftBundle(applicationCaseId)
      .then((bundle) => {
        if (cancelled) return;
        setDraftTabs(bundle.tabs);
        setDraftLoadStatus("ready");
      })
      .catch(() => {
        if (cancelled) return;
        setDraftLoadStatus("error");
        toast.error("Không tải được bản nháp từ máy chủ. Kiểm tra đăng nhập hoặc thử lại.");
      });

    return () => {
      cancelled = true;
    };
  }, [applicationCaseId]);

  useEffect(() => {
    if (reportStepCompleted) return;
    if (reportDraftLooksComplete(draftTabs.report)) {
      setReportStepCompleted(true);
      try {
        sessionStorage.setItem(REPORT_STEP_SESSION_KEY, "1");
      } catch {
        /* ignore */
      }
    }
  }, [draftTabs.report, reportStepCompleted]);

  const persistDraft = useCallback(
    async (tab: "report" | "application" | "contribution", data: Record<string, unknown>) => {
      const bundle = await saveApplicantDraftTab(tab, data, applicationCaseId || undefined);
      setApplicationCaseId(bundle.caseId);
      try {
        sessionStorage.setItem(APPLICANT_CASE_ID_SESSION_KEY, bundle.caseId);
      } catch {
        /* ignore */
      }
      setDraftTabs(bundle.tabs);
      setDraftLoadStatus("ready");
    },
    [applicationCaseId],
  );

  const persistAllDraftTabs = useCallback(
    async (payload: {
      report: Record<string, unknown>;
      application: Record<string, unknown>;
      contribution: Record<string, unknown>;
    }) => {
      await persistDraft("report", payload.report);
      await persistDraft("application", payload.application);
      await persistDraft("contribution", payload.contribution);
    },
    [persistDraft],
  );

  const handleReportNext = useCallback(() => {
    try {
      sessionStorage.setItem(REPORT_STEP_SESSION_KEY, "1");
    } catch {
      /* ignore */
    }
    setReportStepCompleted(true);
    setActiveApplicantTab("application");
  }, []);

  return {
    applicationCaseId,
    draftTabs,
    reportStepCompleted,
    activeApplicantTab,
    setActiveApplicantTab,
    applicantDraftMountKey,
    draftLoadStatus,
    persistDraft,
    persistAllDraftTabs,
    handleReportNext,
  };
}
