import { useCallback, useEffect, useRef, useState } from "react";
import { HttpError } from "../../shared/api/errors";
import type { PageResult } from "../../shared/api/types";
import type { DocumentSummary, MainPlanBrief } from "../documents/documentTypes";
import type { RemotePageState } from "../documents/documentState";
import { attachmentApi } from "./attachmentApi";
import type {
  AttachmentBindingSummary,
  AttachmentListQuery,
  MountedAttachmentQuery,
} from "./attachmentTypes";
import { useContentRevision } from "../../shared/state/contentRefresh";

function toHttpError(error: unknown): HttpError {
  return error instanceof HttpError
    ? error
    : new HttpError({
        httpStatus: 0,
        code: "INTERNAL_ERROR",
        message: "请求失败",
        details: null,
        requestId: "unknown",
        cause: error,
      });
}

function usePage<T>(
  loader: (signal: AbortSignal) => Promise<PageResult<T>>,
  dependencies: readonly unknown[],
  debounceKey: string | undefined,
  enabled = true,
  debounceMs = 300,
): RemotePageState<T> {
  const [state, setState] = useState<RemotePageState<T>>({
    data: null,
    loading: true,
    error: null,
    retry: () => undefined,
  });
  const version = useRef(0);
  const previousDebounceKey = useRef(debounceKey);
  const [retryVersion, setRetryVersion] = useState(0);
  const retry = useCallback(() => setRetryVersion((value) => value + 1), []);

  useEffect(() => {
    if (!enabled) {
      setState((previous) => ({ ...previous, loading: false, error: null, retry }));
      return;
    }
    const current = ++version.current;
    const controller = new AbortController();
    const delay = previousDebounceKey.current === debounceKey ? 0 : debounceMs;
    previousDebounceKey.current = debounceKey;
    const timer = window.setTimeout(() => {
      setState((previous) => ({ ...previous, loading: true, error: null, retry }));
      void loader(controller.signal)
        .then((data) => {
          if (version.current === current) {
            setState({ data, loading: false, error: null, retry });
          }
        })
        .catch((error: unknown) => {
          if (version.current !== current || controller.signal.aborted) return;
          setState({ data: null, loading: false, error: toHttpError(error), retry });
        });
    }, delay);
    return () => {
      window.clearTimeout(timer);
      controller.abort();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [...dependencies, enabled, retryVersion]);

  return { ...state, retry };
}

export function useAttachmentList(
  query: AttachmentListQuery,
): RemotePageState<DocumentSummary> {
  const revision = useContentRevision("attachments");
  return usePage(
    (signal) => attachmentApi.list(query, signal),
    [
      query.keyword,
      query.attachmentType,
      query.fileExtension,
      query.updatedFrom,
      query.updatedTo,
      query.sortBy,
      query.sortDirection,
      query.page,
      query.pageSize,
      revision,
    ],
    query.keyword,
  );
}

export function useMountedAttachments(
  mainPlanId: string | null,
  query: MountedAttachmentQuery,
  enabled = true,
): RemotePageState<AttachmentBindingSummary> {
  const documentRevision = useContentRevision("documents");
  const attachmentRevision = useContentRevision("attachments");
  return usePage(
    (signal) =>
      mainPlanId
        ? attachmentApi.mountedByMainPlan(mainPlanId, query, signal)
        : Promise.resolve({
            items: [],
            page: query.page ?? 1,
            pageSize: query.pageSize ?? 20,
            total: 0,
            totalPages: 0,
          }),
    [
      mainPlanId,
      query.keyword,
      query.attachmentType,
      query.updatedFrom,
      query.updatedTo,
      query.page,
      query.pageSize,
      documentRevision,
      attachmentRevision,
    ],
    query.keyword,
    enabled,
  );
}

export function useAttachmentMainPlans(id: string | null): {
  data: MainPlanBrief[] | null;
  loading: boolean;
  error: HttpError | null;
} {
  const revision = useContentRevision("attachments");
  const [state, setState] = useState<{
    data: MainPlanBrief[] | null;
    loading: boolean;
    error: HttpError | null;
  }>({ data: null, loading: false, error: null });

  useEffect(() => {
    if (!id) {
      setState({ data: null, loading: false, error: null });
      return;
    }
    const controller = new AbortController();
    setState({ data: null, loading: true, error: null });
    void attachmentApi
      .mainPlans(id, controller.signal)
      .then((data) => setState({ data, loading: false, error: null }))
      .catch((error: unknown) => {
        if (!controller.signal.aborted) {
          setState({ data: null, loading: false, error: toHttpError(error) });
        }
      });
    return () => controller.abort();
  }, [id, revision]);

  return state;
}
