import React, { useCallback } from 'react';
import { Box, Text, useInput } from 'ink';
import TextInput from 'ink-text-input';
import type { ParsedCommand, CommandDef } from '@mosaicstack/types';
import { parseSlashCommand, commandRegistry } from '../commands/index.js';
import { CommandAutocomplete } from './command-autocomplete.js';
import { useInputHistory } from '../hooks/use-input-history.js';
import { useState } from 'react';

export interface InputBarProps {
  /** Controlled input value — caller owns the state */
  value: string;
  onChange: (val: string) => void;
  onSubmit: (value: string) => void;
  onSystemMessage?: (message: string) => void;
  onLocalCommand?: (parsed: ParsedCommand) => void;
  onGatewayCommand?: (parsed: ParsedCommand) => void;
  isStreaming: boolean;
  connected: boolean;
  /** Whether this input bar is focused/active (default true). When false,
   *  keyboard input is not captured — e.g. when the sidebar has focus. */
  focused?: boolean;
  placeholder?: string;
  allCommands?: CommandDef[];
}

export function InputBar({
  value: input,
  onChange: setInput,
  onSubmit,
  onSystemMessage,
  onLocalCommand,
  onGatewayCommand,
  isStreaming,
  connected,
  focused = true,
  placeholder: placeholderOverride,
  allCommands,
}: InputBarProps) {
  const [showAutocomplete, setShowAutocomplete] = useState(false);
  const [autocompleteIndex, setAutocompleteIndex] = useState(0);

  const { addToHistory, navigateUp, navigateDown } = useInputHistory();

  // Determine which commands to show in autocomplete
  const availableCommands = allCommands ?? commandRegistry.getAll();

  const handleChange = useCallback(
    (value: string) => {
      setInput(value);
      if (value.startsWith('/')) {
        setShowAutocomplete(true);
        setAutocompleteIndex(0);
      } else {
        setShowAutocomplete(false);
      }
    },
    [setInput],
  );

  const handleSubmit = useCallback(
    (value: string) => {
      if (!value.trim() || isStreaming || !connected) return;

      const trimmed = value.trim();

      addToHistory(trimmed);
      setShowAutocomplete(false);
      setAutocompleteIndex(0);

      if (trimmed.startsWith('/')) {
        const parsed = parseSlashCommand(trimmed);
        if (!parsed) {
          // Bare "/" or malformed — ignore silently (autocomplete handles discovery)
          return;
        }
        const def = commandRegistry.find(parsed.command);
        if (!def) {
          onSystemMessage?.(
            `Unknown command: /${parsed.command}. Type /help for available commands.`,
          );
          setInput('');
          return;
        }
        if (def.execution === 'local') {
          onLocalCommand?.(parsed);
          setInput('');
          return;
        }
        // Gateway-executed commands
        onGatewayCommand?.(parsed);
        setInput('');
        return;
      }

      onSubmit(value);
      setInput('');
    },
    [
      onSubmit,
      onSystemMessage,
      onLocalCommand,
      onGatewayCommand,
      isStreaming,
      connected,
      addToHistory,
      setInput,
    ],
  );

  // Handle Tab: fill in selected autocomplete command
  const fillAutocompleteSelection = useCallback(() => {
    if (!showAutocomplete) return false;
    const query = input.startsWith('/') ? input.slice(1) : input;
    const filtered = availableCommands.filter(
      (c) =>
        !query ||
        c.name.includes(query.toLowerCase()) ||
        c.aliases.some((a) => a.includes(query.toLowerCase())) ||
        c.description.toLowerCase().includes(query.toLowerCase()),
    );
    if (filtered.length === 0) return false;
    const idx = Math.min(autocompleteIndex, filtered.length - 1);
    const selected = filtered[idx];
    if (selected) {
      setInput(`/${selected.name} `);
      setShowAutocomplete(false);
      setAutocompleteIndex(0);
      return true;
    }
    return false;
  }, [showAutocomplete, input, availableCommands, autocompleteIndex, setInput]);

  useInput(
    (_ch, key) => {
      if (key.escape && showAutocomplete) {
        setShowAutocomplete(false);
        setAutocompleteIndex(0);
        return;
      }

      // Tab: fill autocomplete selection
      if (key.tab) {
        fillAutocompleteSelection();
        return;
      }

      // Up arrow
      if (key.upArrow) {
        if (showAutocomplete) {
          setAutocompleteIndex((prev) => Math.max(0, prev - 1));
        } else {
          const prev = navigateUp(input);
          if (prev !== null) {
            setInput(prev);
            if (prev.startsWith('/')) setShowAutocomplete(true);
          }
        }
        return;
      }

      // Down arrow
      if (key.downArrow) {
        if (showAutocomplete) {
          const query = input.startsWith('/') ? input.slice(1) : input;
          const filteredLen = availableCommands.filter(
            (c) =>
              !query ||
              c.name.includes(query.toLowerCase()) ||
              c.aliases.some((a) => a.includes(query.toLowerCase())) ||
              c.description.toLowerCase().includes(query.toLowerCase()),
          ).length;
          const maxVisible = Math.min(filteredLen, 8);
          setAutocompleteIndex((prev) => Math.min(prev + 1, maxVisible - 1));
        } else {
          const next = navigateDown();
          if (next !== null) {
            setInput(next);
            setShowAutocomplete(next.startsWith('/'));
          }
        }
        return;
      }

      // Return/Enter on autocomplete: fill selected command
      if (key.return && showAutocomplete) {
        fillAutocompleteSelection();
        return;
      }
    },
    { isActive: focused },
  );

  const placeholder =
    placeholderOverride ??
    (!connected
      ? 'disconnected — waiting for gateway…'
      : isStreaming
        ? 'waiting for response…'
        : 'message mosaic…');

  return (
    <Box flexDirection="column">
      {showAutocomplete && (
        <CommandAutocomplete
          commands={availableCommands}
          selectedIndex={autocompleteIndex}
          inputValue={input}
        />
      )}
      <Box paddingX={1} borderStyle="single" borderColor="gray">
        <Text bold color="green">
          {'❯ '}
        </Text>
        <TextInput
          value={input}
          onChange={handleChange}
          onSubmit={handleSubmit}
          placeholder={placeholder}
          focus={focused}
        />
      </Box>
    </Box>
  );
}
