import { useEffect, useRef, useState } from "react";
import { HttpError } from "../../shared/api/errors";
import type { PageResult } from "../../shared/api/types";
import type { UserSummary } from "../auth/authTypes";
import {
  organizationApi,
  type OrganizationApi,
} from "./organizationApi";
import {
  userApi,
  type UserApi,
} from "./userApi";
import type {
  OrganizationNode,
  UserQuery,
} from "./directoryTypes";

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

export interface DirectoryError {
  message: string;
  requestId: string;
  httpStatus: number;
}

function toDirectoryError(error: unknown, fallback: string): DirectoryError {
  return error instanceof HttpError
    ? {
        message: error.message,
        requestId: error.requestId,
        httpStatus: error.httpStatus,
      }
    : { message: fallback, requestId: "", httpStatus: 0 };
}

export function flattenOrganizations(
  tree: readonly OrganizationNode[],
): OrganizationNode[] {
  return tree.flatMap((node) => [node, ...flattenOrganizations(node.children)]);
}

export function useOrganizationTree(
  keyword: string,
  retryVersion: number,
  api: OrganizationApi = organizationApi,
  debounceMs = 300,
) {
  const [tree, setTree] = useState<OrganizationNode[]>([]);
  const [status, setStatus] = useState<DirectoryStatus>("loading");
  const [error, setError] = useState<DirectoryError | null>(null);
  const version = useRef(0);

  useEffect(() => {
    const controller = new AbortController();
    const current = ++version.current;
    const timer = window.setTimeout(async () => {
      setStatus("loading");
      setError(null);
      try {
        const result = await api.getTree(
          { keyword: keyword.trim() || undefined },
          controller.signal,
        );
        if (controller.signal.aborted || current !== version.current) return;
        setTree(result);
        setStatus(result.length ? "success" : "empty");
      } catch (loadError) {
        if (controller.signal.aborted || current !== version.current) return;
        setError(toDirectoryError(loadError, "组织树加载失败"));
        setStatus("error");
      }
    }, keyword.trim() ? debounceMs : 0);
    return () => {
      window.clearTimeout(timer);
      controller.abort();
    };
  }, [api, debounceMs, keyword, retryVersion]);

  return { tree, status, error };
}

const EMPTY_USER_PAGE: PageResult<UserSummary> = {
  items: [],
  page: 1,
  pageSize: 20,
  total: 0,
  totalPages: 0,
};

export function useUserDirectory(
  query: UserQuery,
  retryVersion: number,
  api: UserApi = userApi,
  debounceMs = 300,
) {
  const [data, setData] = useState<PageResult<UserSummary>>(EMPTY_USER_PAGE);
  const [status, setStatus] = useState<DirectoryStatus>("loading");
  const [error, setError] = useState<DirectoryError | null>(null);
  const version = useRef(0);
  const {
    organizationId,
    includeDescendants,
    keyword,
    status: enabledStatus,
    page,
    pageSize,
  } = query;

  useEffect(() => {
    const controller = new AbortController();
    const current = ++version.current;
    const timer = window.setTimeout(async () => {
      setStatus("loading");
      setError(null);
      try {
        const result = await api.getUsers(
          {
            organizationId,
            includeDescendants,
            keyword: keyword?.trim() || undefined,
            status: enabledStatus,
            page,
            pageSize: Math.min(pageSize ?? 20, 100),
          },
          controller.signal,
        );
        if (controller.signal.aborted || current !== version.current) return;
        setData(result);
        setStatus(result.items.length ? "success" : "empty");
      } catch (loadError) {
        if (controller.signal.aborted || current !== version.current) return;
        setError(toDirectoryError(loadError, "人员列表加载失败"));
        setStatus("error");
      }
    }, keyword?.trim() ? debounceMs : 0);
    return () => {
      window.clearTimeout(timer);
      controller.abort();
    };
  }, [
    api,
    debounceMs,
    enabledStatus,
    includeDescendants,
    keyword,
    organizationId,
    page,
    pageSize,
    retryVersion,
  ]);

  return { data, status, error };
}

