/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var WorkflowTaskNavigation_exports = {};
__export(WorkflowTaskNavigation_exports, {
  WorkflowTaskFilterProvider: () => WorkflowTaskFilterProvider,
  WorkflowTaskNavigation: () => WorkflowTaskNavigation,
  useWorkflowTaskFilterContext: () => useWorkflowTaskFilterContext
});
module.exports = __toCommonJS(WorkflowTaskNavigation_exports);
var import_icons = require("@ant-design/icons");
var import_css = require("@emotion/css");
var import_antd = require("antd");
var import_react = __toESM(require("react"));
const WorkflowTaskFilterContext = (0, import_react.createContext)({
  selectedWorkflow: null,
  selectWorkflow() {
  },
  workflows: [],
  loading: false,
  loadingMore: false,
  hasNext: false,
  error: false,
  search: "",
  setSearch() {
  },
  loadMore() {
  },
  reload() {
  }
});
function useWorkflowTaskFilterContext() {
  return (0, import_react.useContext)(WorkflowTaskFilterContext);
}
const WORKFLOW_TASK_STATS_PAGE_SIZE = 200;
function isRecord(value) {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function normalizeWorkflowTaskStatsResponse(response) {
  const responseData = isRecord(response) ? response.data : void 0;
  const payload = isRecord(responseData) ? responseData : void 0;
  const rows = Array.isArray(responseData) ? responseData : payload == null ? void 0 : payload.data;
  const meta = isRecord(payload == null ? void 0 : payload.meta) ? payload.meta : void 0;
  return {
    rows: Array.isArray(rows) ? rows.filter(
      (item) => isRecord(item) && typeof item.workflowKey === "string" && typeof item.title === "string" && isRecord(item.stats)
    ) : [],
    hasNext: (meta == null ? void 0 : meta.hasNext) === true
  };
}
function WorkflowTaskFilterProvider(props) {
  const { children, eventBus, loadWorkflowTaskStats, typeKey } = props;
  const [workflowSelection, setWorkflowSelection] = (0, import_react.useState)(null);
  const [workflows, setWorkflows] = (0, import_react.useState)([]);
  const [page, setPage] = (0, import_react.useState)(1);
  const [hasNext, setHasNext] = (0, import_react.useState)(false);
  const [loading, setLoading] = (0, import_react.useState)(false);
  const [loadingMore, setLoadingMore] = (0, import_react.useState)(false);
  const [error, setError] = (0, import_react.useState)(false);
  const [search, setSearch] = (0, import_react.useState)("");
  const requestIdRef = (0, import_react.useRef)(0);
  const previousTypeKeyRef = (0, import_react.useRef)(typeKey);
  const selectedWorkflow = (workflowSelection == null ? void 0 : workflowSelection.typeKey) === typeKey ? workflowSelection.workflow : null;
  const selectWorkflow = (0, import_react.useCallback)(
    (workflow) => {
      setWorkflowSelection(workflow && typeKey ? { typeKey, workflow } : null);
    },
    [typeKey]
  );
  const loadPage = (0, import_react.useCallback)(
    async (nextPage, append) => {
      if (!typeKey) {
        setWorkflows([]);
        setHasNext(false);
        return;
      }
      const requestId = ++requestIdRef.current;
      if (append) {
        setLoadingMore(true);
      } else {
        setLoading(true);
        setHasNext(false);
      }
      setError(false);
      try {
        const response = await loadWorkflowTaskStats({
          type: typeKey,
          page: nextPage,
          pageSize: WORKFLOW_TASK_STATS_PAGE_SIZE,
          ...search ? { search } : {}
        });
        if (requestId !== requestIdRef.current) {
          return;
        }
        const result = normalizeWorkflowTaskStatsResponse(response);
        setWorkflowSelection((selection) => {
          if (!selection || selection.typeKey !== typeKey) {
            return selection;
          }
          const workflow = result.rows.find((item) => item.workflowKey === selection.workflow.workflowKey);
          return workflow ? { ...selection, workflow } : selection;
        });
        setWorkflows((previous) => {
          if (!append) {
            return result.rows;
          }
          const merged = new Map(previous.map((item) => [item.workflowKey, item]));
          result.rows.forEach((item) => merged.set(item.workflowKey, item));
          return Array.from(merged.values());
        });
        setPage(nextPage);
        setHasNext(result.hasNext);
      } catch (loadError) {
        if (requestId === requestIdRef.current) {
          setError(true);
          console.error("Failed to load workflow task stats", loadError);
        }
      } finally {
        if (requestId === requestIdRef.current) {
          setLoading(false);
          setLoadingMore(false);
        }
      }
    },
    [loadWorkflowTaskStats, search, typeKey]
  );
  const reload = (0, import_react.useCallback)(() => {
    loadPage(1, false);
  }, [loadPage]);
  const loadMore = (0, import_react.useCallback)(() => {
    if (!hasNext || loading || loadingMore) {
      return;
    }
    loadPage(page + 1, true);
  }, [hasNext, loadPage, loading, loadingMore, page]);
  (0, import_react.useEffect)(() => {
    if (previousTypeKeyRef.current === typeKey) {
      return;
    }
    previousTypeKeyRef.current = typeKey;
    requestIdRef.current += 1;
    setWorkflowSelection(null);
    setWorkflows([]);
    setPage(1);
    setHasNext(false);
    setSearch("");
  }, [typeKey]);
  (0, import_react.useEffect)(() => {
    reload();
  }, [reload]);
  (0, import_react.useEffect)(() => {
    if (!eventBus) {
      return;
    }
    let timer;
    const onTaskUpdate = (event) => {
      if (!("detail" in event) || !isRecord(event.detail)) {
        return;
      }
      const detail = event.detail;
      if (detail.type !== typeKey) {
        return;
      }
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(reload, 300);
    };
    eventBus.addEventListener("ws:message:workflow:tasks:updated", onTaskUpdate);
    return () => {
      if (timer) {
        clearTimeout(timer);
      }
      eventBus.removeEventListener("ws:message:workflow:tasks:updated", onTaskUpdate);
    };
  }, [eventBus, reload, typeKey]);
  const value = (0, import_react.useMemo)(
    () => ({
      selectedWorkflow,
      selectWorkflow,
      workflows,
      loading,
      loadingMore,
      hasNext,
      error,
      search,
      setSearch,
      loadMore,
      reload
    }),
    [error, hasNext, loadMore, loading, loadingMore, reload, search, selectWorkflow, selectedWorkflow, workflows]
  );
  return /* @__PURE__ */ import_react.default.createElement(WorkflowTaskFilterContext.Provider, { value }, children);
}
function NavigationItemLabel({ count, title }) {
  const { token } = import_antd.theme.useToken();
  return /* @__PURE__ */ import_react.default.createElement(
    "span",
    {
      className: import_css.css`
        display: flex;
        gap: ${token.marginXS}px;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        min-width: 0;

        > span:first-child {
          flex: 1;
          min-width: 0;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        > .ant-badge {
          flex: none;
        }
      `
    },
    /* @__PURE__ */ import_react.default.createElement("span", null, title),
    /* @__PURE__ */ import_react.default.createElement(import_antd.Badge, { count, size: "small" })
  );
}
function WorkflowItemLabel({ title, count }) {
  const { token } = import_antd.theme.useToken();
  return /* @__PURE__ */ import_react.default.createElement(
    "span",
    {
      className: import_css.css`
        display: flex;
        gap: ${token.marginXS}px;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        min-width: 0;

        > span:first-child {
          flex: 1;
          min-width: 0;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
      `
    },
    /* @__PURE__ */ import_react.default.createElement("span", null, title),
    /* @__PURE__ */ import_react.default.createElement(
      "span",
      {
        className: import_css.css`
          flex: none;
          color: ${token.colorTextTertiary};
          font-size: ${token.fontSizeSM}px;
          font-variant-numeric: tabular-nums;
        `
      },
      count
    )
  );
}
function AllWorkflowsLabel(props) {
  const { search, searchValue, setSearchValue, setSearch, t } = props;
  const { token } = import_antd.theme.useToken();
  const [searchExpanded, setSearchExpanded] = (0, import_react.useState)(Boolean(search));
  const [searchFocused, setSearchFocused] = (0, import_react.useState)(false);
  const searchInputRef = (0, import_react.useRef)(null);
  const focusAfterExpandRef = (0, import_react.useRef)(false);
  const isComposingRef = (0, import_react.useRef)(false);
  const suppressSubmitRef = (0, import_react.useRef)(false);
  (0, import_react.useEffect)(() => {
    if (search) {
      setSearchExpanded(true);
    }
  }, [search]);
  (0, import_react.useEffect)(() => {
    var _a;
    if (searchExpanded && focusAfterExpandRef.current) {
      focusAfterExpandRef.current = false;
      (_a = searchInputRef.current) == null ? void 0 : _a.focus();
    }
  }, [searchExpanded]);
  const expandSearchWithFocus = (0, import_react.useCallback)(() => {
    focusAfterExpandRef.current = true;
    setSearchExpanded(true);
  }, []);
  const collapseSearch = (0, import_react.useCallback)(() => {
    if (!searchFocused && !searchValue) {
      setSearchExpanded(false);
    }
  }, [searchFocused, searchValue]);
  return /* @__PURE__ */ import_react.default.createElement(
    "div",
    {
      onMouseLeave: collapseSearch,
      className: import_css.css`
        display: flex;
        align-items: center;
        width: 100%;
        height: ${token.controlHeight}px;
      `
    },
    searchExpanded ? /* @__PURE__ */ import_react.default.createElement(
      "form",
      {
        onMouseDown: (event) => event.stopPropagation(),
        onClick: (event) => event.stopPropagation(),
        onSubmit: (event) => {
          event.preventDefault();
          event.stopPropagation();
          if (isComposingRef.current || suppressSubmitRef.current) {
            suppressSubmitRef.current = false;
            return;
          }
          setSearch(searchValue.trim());
        },
        className: import_css.css`
            width: 100%;
          `
      },
      /* @__PURE__ */ import_react.default.createElement(
        import_antd.Input,
        {
          ref: searchInputRef,
          allowClear: true,
          size: "small",
          value: searchValue,
          placeholder: t("Search workflows"),
          "aria-label": t("Search workflows"),
          onCompositionStart: () => {
            isComposingRef.current = true;
          },
          onCompositionEnd: () => {
            isComposingRef.current = false;
          },
          onFocus: () => setSearchFocused(true),
          onBlur: () => {
            setSearchFocused(false);
            if (!searchValue) {
              setSearchExpanded(false);
            }
          },
          onChange: (event) => {
            const value = event.target.value;
            setSearchValue(value);
            if (!value && search) {
              setSearch("");
            }
          },
          onKeyDown: (event) => {
            event.stopPropagation();
            if (event.key === "Enter") {
              suppressSubmitRef.current = event.nativeEvent.isComposing || isComposingRef.current;
            }
            if (event.key === "Escape") {
              setSearchValue("");
              setSearch("");
              setSearchExpanded(false);
            }
          }
        }
      )
    ) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
      "span",
      {
        className: import_css.css`
              flex: 1;
              min-width: 0;
              overflow: hidden;
              text-overflow: ellipsis;
              white-space: nowrap;
            `
      },
      t("All workflows")
    ), /* @__PURE__ */ import_react.default.createElement(
      "button",
      {
        type: "button",
        "aria-label": t("Search workflows"),
        onMouseDown: (event) => event.stopPropagation(),
        onClick: (event) => {
          event.stopPropagation();
          expandSearchWithFocus();
        },
        onMouseEnter: () => setSearchExpanded(true),
        onFocus: expandSearchWithFocus,
        className: import_css.css`
              display: inline-flex;
              flex: none;
              align-items: center;
              justify-content: flex-end;
              width: ${token.controlHeightSM}px;
              height: ${token.controlHeightSM}px;
              padding: 0;
              color: ${token.colorTextSecondary};
              cursor: pointer;
              background: transparent;
              border: 0;
              border-radius: ${token.borderRadiusSM}px;

              &:hover,
              &:focus-visible {
                color: ${token.colorPrimary};
              }

              &:focus-visible {
                outline: ${token.lineWidthFocus}px solid ${token.colorPrimaryBorder};
                outline-offset: -${token.lineWidthFocus}px;
              }
            `
      },
      /* @__PURE__ */ import_react.default.createElement(import_icons.SearchOutlined, null)
    ))
  );
}
function WorkflowTaskNavigationMenu(props) {
  const { currentTypeKey, onTaskTypeSelect, onWorkflowSelect, taskTypes, t } = props;
  const { token } = import_antd.theme.useToken();
  const {
    selectedWorkflow,
    selectWorkflow,
    workflows,
    loading,
    loadingMore,
    hasNext,
    error,
    search,
    setSearch,
    loadMore,
    reload
  } = useWorkflowTaskFilterContext();
  const [searchValue, setSearchValue] = (0, import_react.useState)(search);
  const typeMenuKey = currentTypeKey ? `type:${currentTypeKey}` : void 0;
  (0, import_react.useEffect)(() => {
    setSearchValue(search);
  }, [search]);
  const handleWorkflowSelect = (0, import_react.useCallback)(
    (workflow) => {
      selectWorkflow(workflow);
      onWorkflowSelect == null ? void 0 : onWorkflowSelect();
    },
    [onWorkflowSelect, selectWorkflow]
  );
  const handleMenuClick = (0, import_react.useCallback)(
    ({ key }) => {
      if (key === "workflow:all") {
        handleWorkflowSelect(null);
        return;
      }
      if (key === "action:retry") {
        reload();
        return;
      }
      if (key === "action:loadMore") {
        loadMore();
        return;
      }
      if (!key.startsWith("workflow:")) {
        return;
      }
      const workflowKey = key.slice("workflow:".length);
      const workflow = workflows.find((item) => item.workflowKey === workflowKey);
      if (workflow) {
        handleWorkflowSelect(workflow);
      }
    },
    [handleWorkflowSelect, loadMore, reload, workflows]
  );
  const handleOpenChange = (0, import_react.useCallback)(
    (openKeys) => {
      const nextTypeMenuKey = [...openKeys].reverse().find((key) => key.startsWith("type:") && key !== typeMenuKey);
      if (!nextTypeMenuKey) {
        selectWorkflow(null);
        return;
      }
      const nextType = nextTypeMenuKey.slice("type:".length);
      if (nextType !== currentTypeKey) {
        onTaskTypeSelect(nextType);
      }
    },
    [currentTypeKey, onTaskTypeSelect, selectWorkflow, typeMenuKey]
  );
  const workflowMenuItems = [
    {
      key: "workflow:all",
      label: /* @__PURE__ */ import_react.default.createElement(
        AllWorkflowsLabel,
        {
          search,
          searchValue,
          setSearchValue,
          setSearch,
          t
        }
      )
    },
    ...workflows.map((workflow) => ({
      key: `workflow:${workflow.workflowKey}`,
      label: /* @__PURE__ */ import_react.default.createElement(WorkflowItemLabel, { title: workflow.title, count: workflow.stats.pending })
    }))
  ];
  if (loading) {
    workflowMenuItems.push({
      key: "status:loading",
      disabled: true,
      label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, /* @__PURE__ */ import_react.default.createElement(import_antd.Spin, { size: "small" }))
    });
  }
  if (error) {
    workflowMenuItems.push({ key: "action:retry", label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, t("Retry")) });
  }
  if (hasNext && !error) {
    workflowMenuItems.push({
      key: "action:loadMore",
      disabled: loadingMore,
      label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, loadingMore ? /* @__PURE__ */ import_react.default.createElement(import_antd.Spin, { size: "small" }) : t("Load more"))
    });
  }
  return /* @__PURE__ */ import_react.default.createElement(
    import_antd.Menu,
    {
      "data-testid": "workflow-task-navigation-menu",
      mode: "inline",
      inlineIndent: token.padding,
      expandIcon: null,
      openKeys: typeMenuKey ? [typeMenuKey] : [],
      selectedKeys: [selectedWorkflow ? `workflow:${selectedWorkflow.workflowKey}` : "workflow:all"],
      onClick: handleMenuClick,
      onOpenChange: handleOpenChange,
      items: taskTypes.map((type) => ({
        key: `type:${type.key}`,
        label: /* @__PURE__ */ import_react.default.createElement(NavigationItemLabel, { title: type.title, count: type.count }),
        children: type.key === currentTypeKey ? workflowMenuItems : [
          {
            key: `placeholder:${type.key}`,
            disabled: true,
            className: "workflow-task-menu-placeholder",
            label: null
          }
        ]
      })),
      className: import_css.css`
        display: flex;
        flex-direction: column;
        height: 100%;
        min-height: 0;
        overflow: hidden;
        background: ${token.colorBgContainer};
        border-inline-end: 0 !important;

        > .ant-menu-submenu {
          flex: none;
          min-height: 0;
        }

        > .ant-menu-submenu-open {
          display: flex;
          flex: 0 1 auto;
          flex-direction: column;
          min-height: ${token.controlHeightLG + token.marginXXS * 2}px;
          overflow: hidden;
        }

        > .ant-menu-submenu-open > .ant-menu-submenu-title {
          flex: none;
        }

        > .ant-menu-submenu-open > .ant-menu-sub.ant-menu-inline {
          flex: 1;
          min-height: 0;
          overflow-x: hidden;
          overflow-y: auto;
          overscroll-behavior: contain;
        }

        .ant-menu-sub.ant-menu-inline {
          width: calc(100% - ${token.marginXXS * 2}px);
          margin-inline: ${token.marginXXS}px;
          padding-block: ${token.paddingXXS}px;
          background: ${token.colorFillTertiary} !important;
          border-radius: ${token.borderRadius}px;
        }

        .ant-menu-submenu-title {
          padding-inline-end: ${token.padding}px;
        }

        .ant-menu-sub.ant-menu-inline > .ant-menu-item {
          height: ${token.controlHeight}px;
          margin-block: 0;
          line-height: ${token.controlHeight}px;
        }

        .ant-menu-title-content {
          min-width: 0;
        }

        .workflow-task-menu-placeholder {
          display: none !important;
        }
      `
    }
  );
}
function WorkflowTaskNavigation(props) {
  const { currentTypeKey, mobile, onTaskTypeSelect, taskTypes, t } = props;
  const { selectedWorkflow } = useWorkflowTaskFilterContext();
  const { token } = import_antd.theme.useToken();
  const [open, setOpen] = (0, import_react.useState)(false);
  const currentType = taskTypes.find((type) => type.key === currentTypeKey);
  if (mobile) {
    return /* @__PURE__ */ import_react.default.createElement(
      import_antd.Layout.Header,
      {
        style: {
          background: token.colorBgContainer,
          height: "auto",
          lineHeight: "normal",
          padding: `${token.paddingXXS}px ${token.padding}px`
        }
      },
      /* @__PURE__ */ import_react.default.createElement(
        import_antd.Button,
        {
          block: true,
          type: "text",
          "aria-expanded": open,
          "aria-label": t("Select workflow"),
          onClick: () => setOpen(true),
          className: import_css.css`
            height: ${token.controlHeight}px;
            padding-inline: ${token.paddingSM}px;
            background: ${token.colorFillAlter};
            border: 0;

            &:hover,
            &:focus-visible {
              background: ${token.colorFillSecondary} !important;
            }
          `
        },
        /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { align: "center", justify: "space-between", gap: token.marginXS, style: { minWidth: 0, width: "100%" } }, /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { align: "center", gap: token.marginXXS, style: { minWidth: 0 } }, /* @__PURE__ */ import_react.default.createElement("span", null, currentType == null ? void 0 : currentType.title), selectedWorkflow ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_icons.RightOutlined, { "aria-hidden": true, style: { color: token.colorTextTertiary, flex: "none" } }), /* @__PURE__ */ import_react.default.createElement(
          "span",
          {
            style: {
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap"
            }
          },
          selectedWorkflow.title
        )) : null), /* @__PURE__ */ import_react.default.createElement(
          import_icons.DownOutlined,
          {
            "aria-hidden": true,
            style: { color: token.colorTextSecondary, flex: "none", marginInlineStart: "auto" }
          }
        ))
      ),
      /* @__PURE__ */ import_react.default.createElement(
        import_antd.Drawer,
        {
          title: t("Workflow tasks"),
          placement: "left",
          open,
          onClose: () => setOpen(false),
          styles: { body: { padding: 0 } }
        },
        /* @__PURE__ */ import_react.default.createElement(
          WorkflowTaskNavigationMenu,
          {
            currentTypeKey,
            onTaskTypeSelect,
            onWorkflowSelect: () => setOpen(false),
            taskTypes,
            t
          }
        )
      )
    );
  }
  return /* @__PURE__ */ import_react.default.createElement(
    import_antd.Layout.Sider,
    {
      theme: "light",
      breakpoint: "md",
      collapsedWidth: 0,
      style: {
        background: token.colorBgContainer,
        borderInlineEnd: `${token.lineWidth}px ${token.lineType} ${token.colorBorderSecondary}`
      }
    },
    /* @__PURE__ */ import_react.default.createElement(
      WorkflowTaskNavigationMenu,
      {
        currentTypeKey,
        onTaskTypeSelect,
        taskTypes,
        t
      }
    )
  );
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  WorkflowTaskFilterProvider,
  WorkflowTaskNavigation,
  useWorkflowTaskFilterContext
});
