import { jsx, jsxs } from "react/jsx-runtime";
import React, {
  useState,
  useEffect,
  useRef,
  useMemo,
  useCallback,
  forwardRef,
  useImperativeHandle
} from "react";
import { Box, Text } from "ink";
import { getAvailableCommands } from "../interactive-commands/commands.js";
import { useTerminalSize } from "../hooks/useTerminalSize.js";
import { getMaxVisibleItemsForTerminalRows } from "../utils/overlaySizing.js";
import { supportsPrompts } from "../agent-backend.js";
function getPromptMatchScore(prompt, query) {
  if (!query) return 3;
  const lowerQuery = query.toLowerCase();
  const name = prompt.name.toLowerCase();
  const description = (prompt.description || "").toLowerCase();
  const title = (prompt.title || "").toLowerCase();
  if (name.startsWith(lowerQuery)) {
    return 3;
  }
  if (name.includes(lowerQuery)) {
    return 2;
  }
  if (description.includes(lowerQuery) || title.includes(lowerQuery)) {
    return 1;
  }
  return 0;
}
function matchesPromptQuery(prompt, query) {
  return getPromptMatchScore(prompt, query) > 0;
}
function getSystemCommandMatchScore(cmd, query) {
  if (!query) return 4;
  const lowerQuery = query.toLowerCase();
  const name = cmd.name.toLowerCase();
  const description = (cmd.description || "").toLowerCase();
  if (name.startsWith(lowerQuery)) {
    return 4;
  }
  if (name.includes(lowerQuery)) {
    return 3;
  }
  if (cmd.aliases) {
    for (const alias of cmd.aliases) {
      const lowerAlias = alias.toLowerCase();
      if (lowerAlias.startsWith(lowerQuery)) {
        return 2;
      }
      if (lowerAlias.includes(lowerQuery)) {
        return 2;
      }
    }
  }
  if (description.includes(lowerQuery)) {
    return 1;
  }
  return 0;
}
function matchesSystemCommandQuery(cmd, query) {
  return getSystemCommandMatchScore(cmd, query) > 0;
}
const SlashCommandAutocompleteInner = forwardRef(function SlashCommandAutocomplete({
  isVisible,
  searchQuery,
  onSelectPrompt,
  onSelectSystemCommand,
  onLoadIntoInput,
  onSubmitRaw,
  onClose,
  agent
}, ref) {
  const [prompts, setPrompts] = useState([]);
  const [systemCommands, setSystemCommands] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const { columns: terminalWidth, rows: terminalRows } = useTerminalSize();
  const maxVisibleItems = useMemo(() => {
    return getMaxVisibleItemsForTerminalRows({
      rows: terminalRows,
      hardCap: 8,
      reservedRows: 8
    });
  }, [terminalRows]);
  const [selection, setSelection] = useState({ index: 0, offset: 0 });
  const selectedIndexRef = useRef(0);
  const updateSelection = useCallback(
    (indexUpdater) => {
      setSelection((prev) => {
        const newIndex = typeof indexUpdater === "function" ? indexUpdater(prev.index) : indexUpdater;
        selectedIndexRef.current = newIndex;
        let newOffset = prev.offset;
        if (newIndex < prev.offset) {
          newOffset = newIndex;
        } else if (newIndex >= prev.offset + maxVisibleItems) {
          newOffset = Math.max(0, newIndex - maxVisibleItems + 1);
        }
        return { index: newIndex, offset: newOffset };
      });
    },
    [maxVisibleItems]
  );
  useEffect(() => {
    if (!isVisible) return;
    let cancelled = false;
    setIsLoading(true);
    const fetchCommands = async () => {
      try {
        const promptList = supportsPrompts(agent) ? Object.values(await agent.listPrompts()).map((p) => ({
          ...p,
          kind: "prompt"
        })) : [];
        const allCommands = getAvailableCommands(agent);
        const commandList = allCommands.map((cmd) => ({
          kind: "system",
          name: cmd.name,
          description: cmd.description,
          ...cmd.category && { category: cmd.category },
          ...cmd.aliases && { aliases: cmd.aliases }
        }));
        if (!cancelled) {
          setPrompts(promptList);
          setSystemCommands(commandList);
          setIsLoading(false);
        }
      } catch {
        if (!cancelled) {
          setPrompts([]);
          setSystemCommands([]);
          setIsLoading(false);
        }
      }
    };
    void fetchCommands();
    return () => {
      cancelled = true;
    };
  }, [isVisible, agent]);
  const commandQuery = useMemo(() => {
    if (!searchQuery.startsWith("/")) return "";
    const afterSlash = searchQuery.slice(1).trim();
    const spaceIndex = afterSlash.indexOf(" ");
    return spaceIndex > 0 ? afterSlash.slice(0, spaceIndex) : afterSlash;
  }, [searchQuery]);
  const filteredPrompts = useMemo(() => {
    if (!commandQuery) {
      return prompts;
    }
    return prompts.filter((p) => matchesPromptQuery(p, commandQuery)).sort((a, b) => {
      const scoreA = getPromptMatchScore(a, commandQuery);
      const scoreB = getPromptMatchScore(b, commandQuery);
      return scoreB - scoreA;
    });
  }, [prompts, commandQuery]);
  const filteredSystemCommands = useMemo(() => {
    if (!commandQuery) {
      return systemCommands;
    }
    return systemCommands.filter((cmd) => matchesSystemCommandQuery(cmd, commandQuery)).sort((a, b) => {
      const scoreA = getSystemCommandMatchScore(a, commandQuery);
      const scoreB = getSystemCommandMatchScore(b, commandQuery);
      return scoreB - scoreA;
    });
  }, [systemCommands, commandQuery]);
  const hasArguments = useMemo(() => {
    if (!searchQuery.startsWith("/")) return false;
    const afterSlash = searchQuery.slice(1).trim();
    return afterSlash.includes(" ");
  }, [searchQuery]);
  const combinedItems = useMemo(() => {
    const items = [];
    if (hasArguments) {
      const exactSystemCmd = systemCommands.find(
        (cmd) => cmd.name.toLowerCase() === commandQuery.toLowerCase()
      );
      if (exactSystemCmd) {
        items.push({ kind: "system", command: exactSystemCmd });
      }
      const exactPrompt = prompts.find(
        (p) => p.name.toLowerCase() === commandQuery.toLowerCase() || p.displayName && p.displayName.toLowerCase() === commandQuery.toLowerCase()
      );
      if (exactPrompt) {
        items.push({ kind: "prompt", prompt: exactPrompt });
      }
      return items;
    }
    filteredSystemCommands.forEach((cmd) => items.push({ kind: "system", command: cmd }));
    filteredPrompts.forEach((prompt) => items.push({ kind: "prompt", prompt }));
    return items;
  }, [
    hasArguments,
    filteredPrompts,
    filteredSystemCommands,
    systemCommands,
    prompts,
    commandQuery
  ]);
  const getFirstItemId = () => {
    const first = combinedItems[0];
    if (!first) return null;
    if (first.kind === "system") return `sys:${first.command.name}`;
    return `prompt:${first.prompt.name}`;
  };
  const currentFirstId = getFirstItemId();
  const prevItemsRef = useRef({ length: combinedItems.length, firstId: currentFirstId });
  const itemsChanged = combinedItems.length !== prevItemsRef.current.length || currentFirstId !== prevItemsRef.current.firstId;
  const selectedIndex = itemsChanged ? 0 : Math.min(selection.index, Math.max(0, combinedItems.length - 1));
  const scrollOffset = itemsChanged ? 0 : Math.min(selection.offset, Math.max(0, combinedItems.length - maxVisibleItems));
  useEffect(() => {
    if (itemsChanged) {
      prevItemsRef.current = { length: combinedItems.length, firstId: currentFirstId };
      if (selection.index !== 0 || selection.offset !== 0) {
        selectedIndexRef.current = 0;
        setSelection({ index: 0, offset: 0 });
      } else {
        selectedIndexRef.current = 0;
      }
    }
  }, [itemsChanged, combinedItems.length, currentFirstId, selection.index, selection.offset]);
  const visibleItems = useMemo(() => {
    return combinedItems.slice(scrollOffset, scrollOffset + maxVisibleItems);
  }, [combinedItems, scrollOffset, maxVisibleItems]);
  useImperativeHandle(
    ref,
    () => ({
      handleInput: (input, key) => {
        if (!isVisible) return false;
        if (key.escape) {
          onClose();
          return true;
        }
        const itemsLength = combinedItems.length;
        if (itemsLength === 0 || hasArguments) {
          if (key.return) {
            void Promise.resolve(onSubmitRaw?.(searchQuery)).catch((err) => {
              const message = err instanceof Error ? err.message : String(err);
              agent.logger.error(
                `SlashCommandAutocomplete: Failed to submit raw command: ${message}`
              );
            });
            onClose();
            return true;
          }
          return false;
        }
        if (key.upArrow) {
          updateSelection((prev) => (prev - 1 + itemsLength) % itemsLength);
          return true;
        }
        if (key.downArrow) {
          updateSelection((prev) => (prev + 1) % itemsLength);
          return true;
        }
        if (key.tab) {
          const item = combinedItems[selectedIndexRef.current];
          if (!item) return false;
          const interactiveCommands = ["model", "resume", "switch"];
          const isInteractiveCommand = item.kind === "system" && interactiveCommands.includes(item.command.name);
          if (isInteractiveCommand && item.kind === "system") {
            onSelectSystemCommand?.(item.command.name);
          } else if (item.kind === "system") {
            onLoadIntoInput?.(`/${item.command.name}`);
          } else {
            const cmdName = item.prompt.commandName || item.prompt.displayName || item.prompt.name;
            const argsString = item.prompt.arguments && item.prompt.arguments.length > 0 ? " " + item.prompt.arguments.map((arg) => `<${arg.name}${arg.required ? "" : "?"}>`).join(" ") : "";
            onLoadIntoInput?.(`/${cmdName}${argsString}`);
          }
          return true;
        }
        if (key.return) {
          const item = combinedItems[selectedIndexRef.current];
          if (!item) return false;
          if (item.kind === "system") {
            onSelectSystemCommand?.(item.command.name);
          } else {
            onSelectPrompt(item.prompt);
          }
          onClose();
          return true;
        }
        return false;
      }
    }),
    [
      isVisible,
      combinedItems,
      hasArguments,
      selectedIndexRef,
      searchQuery,
      onClose,
      onLoadIntoInput,
      onSubmitRaw,
      onSelectPrompt,
      onSelectSystemCommand,
      updateSelection,
      agent
    ]
  );
  if (!isVisible) return null;
  if (isLoading) {
    return /* @__PURE__ */ jsx(Box, { width: terminalWidth, paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Loading commands..." }) });
  }
  if (combinedItems.length === 0) {
    return null;
  }
  const nameColumnWidth = Math.max(16, Math.min(28, Math.floor(terminalWidth * 0.32)));
  const descriptionColor = (isSelected) => isSelected ? "white" : "gray";
  const commandColor = (isSelected) => isSelected ? "cyan" : "gray";
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: terminalWidth, children: visibleItems.map((item, visibleIndex) => {
    const actualIndex = scrollOffset + visibleIndex;
    const isSelected = actualIndex === selectedIndex;
    if (item.kind === "system") {
      const cmd = item.command;
      const nameText2 = `/${cmd.name}`;
      const descText = cmd.description || "";
      return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
        /* @__PURE__ */ jsx(Box, { marginRight: 1, children: /* @__PURE__ */ jsx(Text, { color: commandColor(isSelected), children: isSelected ? "\u276F" : " " }) }),
        /* @__PURE__ */ jsx(Box, { width: nameColumnWidth, children: /* @__PURE__ */ jsx(
          Text,
          {
            wrap: "truncate-end",
            color: commandColor(isSelected),
            bold: isSelected,
            children: nameText2
          }
        ) }),
        /* @__PURE__ */ jsx(Box, { flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", color: descriptionColor(isSelected), children: descText }) })
      ] }, `system-${cmd.name}`);
    }
    const prompt = item.prompt;
    const displayName = prompt.displayName || prompt.name;
    const hasCollision = prompt.commandName && prompt.commandName !== displayName;
    const nameText = `/${displayName}`;
    const argsString = prompt.arguments && prompt.arguments.length > 0 ? " " + prompt.arguments.map((arg) => `<${arg.name}${arg.required ? "" : "?"}>`).join(" ") : "";
    const description = prompt.title || prompt.description || "";
    const commandText = nameText + argsString;
    const collisionSuffix = hasCollision ? ` (use /${prompt.commandName})` : "";
    return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
      /* @__PURE__ */ jsx(Box, { marginRight: 1, children: /* @__PURE__ */ jsx(Text, { color: commandColor(isSelected), children: isSelected ? "\u276F" : " " }) }),
      /* @__PURE__ */ jsx(Box, { width: nameColumnWidth, children: /* @__PURE__ */ jsx(
        Text,
        {
          wrap: "truncate-end",
          color: commandColor(isSelected),
          bold: isSelected,
          children: commandText
        }
      ) }),
      /* @__PURE__ */ jsx(Box, { flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", color: descriptionColor(isSelected), children: [
        description,
        collisionSuffix
      ] }) })
    ] }, `prompt-${prompt.name}`);
  }) });
});
const SlashCommandAutocomplete2 = React.memo(
  SlashCommandAutocompleteInner
);
export {
  SlashCommandAutocomplete2 as SlashCommandAutocomplete
};
