import { useCallback, useEffect, useRef, useState } from "react";
import { HttpError } from "../../shared/api/errors";
import { useContentRevision } from "../../shared/state/contentRefresh";
import {
  categoryApi,
  type CategoryApi,
} from "./categoryApi";
import type { CategoryNode } from "./categoryTypes";

export type CategoryLoadStatus = "loading" | "success" | "empty" | "error";

export interface CategoryLoadError {
  message: string;
  requestId: string;
  code: string;
  httpStatus: number;
}

export function toCategoryLoadError(error: unknown): CategoryLoadError {
  if (error instanceof HttpError) {
    return {
      message: error.message,
      requestId: error.requestId,
      code: error.code,
      httpStatus: error.httpStatus,
    };
  }
  return {
    message: "分类树加载失败",
    requestId: "",
    code: "INTERNAL_ERROR",
    httpStatus: 0,
  };
}

export function useCategoryTree(
  api: CategoryApi = categoryApi,
  debounceMs = 300,
) {
  const [keyword, setKeyword] = useState("");
  const [tree, setTree] = useState<CategoryNode[]>([]);
  const [status, setStatus] = useState<CategoryLoadStatus>("loading");
  const [error, setError] = useState<CategoryLoadError | null>(null);
  const [refreshVersion, setRefreshVersion] = useState(0);
  const requestVersion = useRef(0);
  const documentRevision = useContentRevision("documents");

  const refresh = useCallback(() => {
    setRefreshVersion((value) => value + 1);
  }, []);

  useEffect(() => {
    const controller = new AbortController();
    const currentRequest = ++requestVersion.current;
    const timer = window.setTimeout(async () => {
      setStatus("loading");
      setError(null);
      try {
        const nextTree = await api.getTree(
          { keyword: keyword.trim() || undefined },
          controller.signal,
        );
        if (controller.signal.aborted || currentRequest !== requestVersion.current) {
          return;
        }
        setTree(nextTree);
        setStatus(nextTree.length ? "success" : "empty");
      } catch (loadError) {
        if (controller.signal.aborted || currentRequest !== requestVersion.current) {
          return;
        }
        if (loadError instanceof HttpError && loadError.message === "请求已取消") {
          return;
        }
        setError(toCategoryLoadError(loadError));
        setStatus("error");
      }
    }, keyword.trim() ? debounceMs : 0);

    return () => {
      window.clearTimeout(timer);
      controller.abort();
    };
  }, [api, debounceMs, documentRevision, keyword, refreshVersion]);

  return {
    keyword,
    setKeyword,
    tree,
    status,
    error,
    refresh,
  };
}
