import React, {
  KeyboardEvent,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import { ChevronDown, ChevronUp } from 'lucide-react';
import {
  PortfolioAction,
  PortfolioActionDraft,
} from '../../types/terminal';
import {
  getTerminalCommandSpec,
  getTerminalCommandSpecForAction,
  TERMINAL_COMMAND_SUGGESTIONS,
} from '../../lib/terminalCommandSpecs';
import {
  buildCommandSignature,
  resolveTerminalShadow,
} from '../../lib/terminalShadow';

interface CommandInputProps {
  onSubmit: (command: string) => void;
  onStartPortfolioAction: (action: PortfolioAction) => void;
  onUpdatePortfolioDraft: (patch: Partial<PortfolioActionDraft>) => void;
  onClearPortfolioAction: () => void;
  isProcessing: boolean;
  resetCommandIndex: () => void;
  portfolioMode: boolean;
  activePortfolioAction: PortfolioAction | null;
  portfolioDraft: PortfolioActionDraft;
  lastPortfolioCommand: string | null;
  placeholder?: string;
}

export interface CommandInputHandle {
  focusWithText: (text: string) => void;
}

const ACTION_LABELS: Record<'buy' | 'sell' | 'deposit' | 'withdraw', string> = {
  buy: 'Buy',
  sell: 'Sell',
  deposit: 'Deposit',
  withdraw: 'Withdraw',
};

const isActionComposer = (
  action: PortfolioAction | null,
): action is 'buy' | 'sell' | 'deposit' | 'withdraw' =>
  action === 'buy' || action === 'sell' || action === 'deposit' || action === 'withdraw';

const suggestionToAction = (
  command: string,
): 'buy' | 'sell' | 'deposit' | 'withdraw' | null => {
  return getTerminalCommandSpec(command)?.portfolioAction ?? null;
};

const buildGeneratedCommand = (
  action: 'buy' | 'sell' | 'deposit' | 'withdraw',
  draft: PortfolioActionDraft,
) => {
  const spec = getTerminalCommandSpecForAction(action);
  if (action === 'buy' || action === 'sell') {
    const symbol = draft.symbol.trim().toUpperCase();
    const quantity = draft.quantity.trim();
    const price = draft.price.trim();
    const signature = spec
      ? buildCommandSignature(spec, [symbol, quantity, price])
      : `/${action} <ticker> <quantity> [price]`;

    if (!symbol) {
      return { command: signature, error: 'Ticker symbol is required.' };
    }
    if (!quantity) {
      return { command: signature, error: 'Quantity is required.' };
    }
    if (Number.isNaN(Number(quantity)) || Number(quantity) <= 0) {
      return { command: signature, error: 'Quantity must be greater than zero.' };
    }
    if (price && (Number.isNaN(Number(price)) || Number(price) <= 0)) {
      return {
        command: signature,
        error: 'Price must be greater than zero when provided.',
      };
    }

    return {
      command: signature,
      error: null,
    };
  }

  const amount = draft.amount.trim();
  const signature = spec
    ? buildCommandSignature(spec, [amount])
    : `/cash ${action === 'deposit' ? 'deposit' : 'withdraw'} <amount>`;
  if (!amount) {
    return {
      command: signature,
      error: 'Amount is required.',
    };
  }
  if (Number.isNaN(Number(amount)) || Number(amount) <= 0) {
    return {
      command: signature,
      error: 'Amount must be greater than zero.',
    };
  }

  return {
    command: signature,
    error: null,
  };
};

export const CommandInput = React.forwardRef<CommandInputHandle, CommandInputProps>(
  (
    {
      onSubmit,
      onStartPortfolioAction,
      onUpdatePortfolioDraft,
      onClearPortfolioAction,
      isProcessing,
      resetCommandIndex,
      portfolioMode,
      activePortfolioAction,
      portfolioDraft,
      lastPortfolioCommand,
      placeholder = 'Type command or natural language query...',
    },
    ref,
  ) => {
    const [input, setInput] = useState('');
    const [showSuggestions, setShowSuggestions] = useState(false);
    const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(0);
    const [shadowCollapsed, setShadowCollapsed] = useState(false);
    const inputRef = useRef<HTMLInputElement>(null);
    const actionPrimaryFieldRef = useRef<HTMLInputElement>(null);

    const actionComposerActive = isActionComposer(activePortfolioAction);
    const actionMeta = useMemo(
      () =>
        actionComposerActive
          ? buildGeneratedCommand(activePortfolioAction, portfolioDraft)
          : null,
      [actionComposerActive, activePortfolioAction, portfolioDraft],
    );
    const shadowState = useMemo(
      () => (actionComposerActive ? null : resolveTerminalShadow(input)),
      [actionComposerActive, input],
    );

    useEffect(() => {
      if (!isProcessing) {
        if (actionComposerActive) {
          actionPrimaryFieldRef.current?.focus();
        } else {
          inputRef.current?.focus();
        }
      }
    }, [actionComposerActive, isProcessing]);

    const suggestionMatches = useMemo(
      () =>
        TERMINAL_COMMAND_SUGGESTIONS.filter(
          (suggestion) => !input || suggestion.command.startsWith(input),
        ),
      [input],
    );

    useEffect(() => {
      if (!showSuggestions || suggestionMatches.length === 0) {
        setActiveSuggestionIndex(0);
        return;
      }

      setActiveSuggestionIndex((current) =>
        Math.min(current, suggestionMatches.length - 1),
      );
    }, [showSuggestions, suggestionMatches]);

    useImperativeHandle(
      ref,
      () => ({
        focusWithText: (text: string) => {
          setInput(text);
          setShowSuggestions(text.startsWith('/'));
          setActiveSuggestionIndex(0);
          resetCommandIndex();
          inputRef.current?.focus();
        },
      }),
      [resetCommandIndex],
    );

    const handleSubmit = () => {
      const trimmed = input.trim();
      if (trimmed && !isProcessing) {
        onSubmit(trimmed);
        setInput('');
        setShowSuggestions(false);
        setActiveSuggestionIndex(0);
        resetCommandIndex();
      }
    };

    const handleActionSubmit = () => {
      if (!actionComposerActive || !actionMeta || actionMeta.error || isProcessing) {
        return;
      }

      onSubmit(actionMeta.command);
      onClearPortfolioAction();
      setInput('');
      setShowSuggestions(false);
      setActiveSuggestionIndex(0);
      resetCommandIndex();
    };

    const activateSuggestion = (command: string) => {
      const action = suggestionToAction(command);
      if (action) {
        onStartPortfolioAction(action);
        setInput('');
        setShowSuggestions(false);
        setActiveSuggestionIndex(0);
        resetCommandIndex();
        return;
      }

      setInput(`${command} `);
      setShowSuggestions(false);
      setActiveSuggestionIndex(0);
      inputRef.current?.focus();
    };

    const moveSuggestionSelection = (direction: -1 | 1) => {
      if (!showSuggestions || suggestionMatches.length === 0) {
        return;
      }

      setActiveSuggestionIndex((current) => {
        const next = current + direction;
        if (next < 0) {
          return suggestionMatches.length - 1;
        }
        if (next >= suggestionMatches.length) {
          return 0;
        }
        return next;
      });
    };

    const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
      if (event.key === 'Enter') {
        event.preventDefault();
        if (showSuggestions && suggestionMatches[activeSuggestionIndex]) {
          activateSuggestion(suggestionMatches[activeSuggestionIndex].command);
          return;
        }
        handleSubmit();
      } else if (event.key === 'ArrowUp') {
        event.preventDefault();
        moveSuggestionSelection(-1);
      } else if (event.key === 'ArrowDown') {
        event.preventDefault();
        moveSuggestionSelection(1);
      } else if (event.key === 'Tab') {
        event.preventDefault();
        if (showSuggestions) {
          const match = suggestionMatches[activeSuggestionIndex] ?? suggestionMatches[0];
          if (match) {
            activateSuggestion(match.command);
          }
        }
      } else if (event.key === 'Escape') {
        setShowSuggestions(false);
        setActiveSuggestionIndex(0);
      }
    };

    const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
      setInput(event.target.value);
      setShowSuggestions(event.target.value.startsWith('/'));
      setActiveSuggestionIndex(0);
    };

    const helperText = actionComposerActive
      ? `Running ${actionMeta?.command ?? lastPortfolioCommand ?? '/portfolio'} will keep raw terminal output in view.`
      : shadowState
        ? shadowState.helperText
      : portfolioMode
        ? 'Portfolio tools stay active while you move between overview, history, stats, and trade actions.'
        : 'Use /portfolio to load interactive portfolio tools.';

    return (
      <div className="relative min-w-0">
        {actionComposerActive && actionMeta ? (
          <div className="mb-3 border border-[#2a2a2a] bg-[#111111]">
            <div className="flex items-center justify-between border-b border-[#1f1f1f] px-4 py-2">
              <div className="text-xs font-mono text-[#e0e0e0]">
                {ACTION_LABELS[activePortfolioAction]}
              </div>
              <button
                type="button"
                onClick={onClearPortfolioAction}
                className="text-[11px] font-mono text-[#888888] transition-colors hover:text-[#e0e0e0]"
              >
                Use raw command instead
              </button>
            </div>

            <div className="grid gap-3 px-4 py-3 md:grid-cols-3">
              {(activePortfolioAction === 'buy' || activePortfolioAction === 'sell') && (
                <>
                  <label className="flex flex-col gap-1 text-[11px] font-mono text-[#888888]">
                    <span>Symbol</span>
                    <input
                      ref={actionPrimaryFieldRef}
                      type="text"
                      value={portfolioDraft.symbol}
                      onChange={(event) =>
                        onUpdatePortfolioDraft({ symbol: event.target.value.toUpperCase() })
                      }
                      disabled={isProcessing}
                      className="border border-[#2a2a2a] bg-[#0d0d0d] px-3 py-2 text-sm text-[#e0e0e0] outline-none transition-colors focus:border-[#58a6ff]"
                    />
                  </label>
                  <label className="flex flex-col gap-1 text-[11px] font-mono text-[#888888]">
                    <span>Quantity</span>
                    <input
                      type="number"
                      min="0"
                      step="any"
                      value={portfolioDraft.quantity}
                      onChange={(event) =>
                        onUpdatePortfolioDraft({ quantity: event.target.value })
                      }
                      disabled={isProcessing}
                      className="border border-[#2a2a2a] bg-[#0d0d0d] px-3 py-2 text-sm text-[#e0e0e0] outline-none transition-colors focus:border-[#58a6ff]"
                    />
                  </label>
                  <label className="flex flex-col gap-1 text-[11px] font-mono text-[#888888]">
                    <span>Price (optional)</span>
                    <input
                      type="number"
                      min="0"
                      step="any"
                      value={portfolioDraft.price}
                      onChange={(event) =>
                        onUpdatePortfolioDraft({ price: event.target.value })
                      }
                      disabled={isProcessing}
                      className="border border-[#2a2a2a] bg-[#0d0d0d] px-3 py-2 text-sm text-[#e0e0e0] outline-none transition-colors focus:border-[#58a6ff]"
                    />
                  </label>
                </>
              )}

              {(activePortfolioAction === 'deposit' || activePortfolioAction === 'withdraw') && (
                <label className="flex flex-col gap-1 text-[11px] font-mono text-[#888888] md:col-span-2">
                  <span>Amount</span>
                  <input
                    ref={actionPrimaryFieldRef}
                    type="number"
                    min="0"
                    step="any"
                    value={portfolioDraft.amount}
                    onChange={(event) =>
                      onUpdatePortfolioDraft({ amount: event.target.value })
                    }
                    disabled={isProcessing}
                    className="border border-[#2a2a2a] bg-[#0d0d0d] px-3 py-2 text-sm text-[#e0e0e0] outline-none transition-colors focus:border-[#58a6ff]"
                  />
                </label>
              )}
            </div>

            <div className="border-t border-[#1f1f1f] px-4 py-3">
              <div className="text-[10px] font-mono uppercase tracking-[0.18em] text-[#666666]">
                Command Preview
              </div>
              <div className="mt-2 border border-[#1f1f1f] bg-[#0d0d0d] px-3 py-2 font-mono text-sm text-[#e0e0e0]">
                {actionMeta.command}
              </div>
              <div className="mt-2 flex items-center justify-between gap-3">
                <div className="min-h-[18px] text-[11px] font-mono text-[#ff4757]">
                  {actionMeta.error}
                </div>
                <button
                  type="button"
                  onClick={handleActionSubmit}
                  disabled={Boolean(actionMeta.error) || isProcessing}
                  className="border border-[#2a2a2a] bg-[#161616] px-3 py-2 text-xs font-mono text-[#e0e0e0] transition-colors hover:border-[#58a6ff] hover:text-[#58a6ff] disabled:cursor-not-allowed disabled:opacity-40"
                >
                  {isProcessing
                    ? `Running ${actionMeta.command.split(' ')[0]}...`
                    : `Run ${ACTION_LABELS[activePortfolioAction]}`}
                </button>
              </div>
            </div>
          </div>
        ) : null}

        {!actionComposerActive && shadowState ? (
          <div className="mb-2 border border-[#1f1f1f] bg-[#111111]">
            <div className="flex items-center justify-between px-3 py-1.5 border-b border-[#1a1a1a]">
              <span className="text-[9px] font-mono uppercase tracking-wider text-[#666666]">
                Command Shadow
              </span>
              <div className="flex items-center gap-2">
                <span
                  className={`text-[9px] font-mono ${
                    shadowState.readyToRun && !shadowState.hasExtraInput
                      ? 'text-[#3fb950]'
                      : shadowState.mode === 'predictive'
                        ? 'text-[#58a6ff]'
                        : 'text-[#888888]'
                  }`}
                >
                  {shadowState.readyToRun && !shadowState.hasExtraInput
                    ? 'Ready'
                    : shadowState.mode === 'predictive'
                      ? 'Autocomplete'
                      : 'Fill Parameters'}
                </span>
                <button
                  type="button"
                  onClick={() => setShadowCollapsed(!shadowCollapsed)}
                  className="text-[#888888] hover:text-[#e0e0e0] transition-colors"
                >
                  {shadowCollapsed ? (
                    <ChevronDown className="h-3 w-3" />
                  ) : (
                    <ChevronUp className="h-3 w-3" />
                  )}
                </button>
              </div>
            </div>

            {!shadowCollapsed && (
              <>
                <div className="px-3 py-2 border-b border-[#1a1a1a]">
                  <code className="text-xs font-mono text-[#e0e0e0]">
                    {shadowState.signature}
                  </code>
                </div>

                <div className="px-3 py-2">
                  {shadowState.arguments.length > 0 ? (
                    <div className="flex flex-wrap gap-2">
                      {shadowState.arguments.map((argument, index) => (
                        <div
                          key={`${shadowState.spec.command}-${argument.spec.key}`}
                          className={`px-2 py-1 border text-[10px] font-mono transition-colors ${
                            argument.isActive
                              ? 'border-[#58a6ff] bg-[#0f1b2d] text-[#58a6ff]'
                              : argument.isFilled
                                ? 'border-[#1f3d2d] bg-[#0f1712] text-[#3fb950]'
                                : 'border-[#2a2a2a] bg-[#161616] text-[#666666]'
                          }`}
                        >
                          <span className="text-[#888888]">{index + 1}.</span> {argument.spec.label}
                          {argument.spec.required && (
                            <span className="ml-1 text-[#ffb86c]">*</span>
                          )}
                        </div>
                      ))}
                    </div>
                  ) : (
                    <span className="text-[10px] font-mono text-[#666666]">
                      No parameters required
                    </span>
                  )}
                </div>

                {shadowState.spec.examples?.length && shadowState.spec.examples.length > 0 && (
                  <div className="px-3 py-2 border-t border-[#1a1a1a]">
                    <div className="flex flex-wrap gap-1.5">
                      {shadowState.spec.examples.slice(0, 3).map((example) => (
                        <button
                          key={example}
                          type="button"
                          onClick={() => {
                            setInput(example);
                            setShowSuggestions(false);
                            setActiveSuggestionIndex(0);
                            resetCommandIndex();
                            inputRef.current?.focus();
                          }}
                          className="text-[9px] font-mono px-2 py-0.5 border border-[#2a2a2a] text-[#888888] hover:border-[#58a6ff] hover:text-[#58a6ff] transition-colors"
                        >
                          {example}
                        </button>
                      ))}
                      {shadowState.spec.examples.length > 3 && (
                        <span className="text-[9px] font-mono text-[#666666]">
                          +{shadowState.spec.examples.length - 3} more
                        </span>
                      )}
                    </div>
                  </div>
                )}
              </>
            )}
          </div>
        ) : null}

        {showSuggestions && suggestionMatches.length > 0 ? (
          <div className="absolute inset-x-0 top-full z-20 mt-2 max-h-[320px] overflow-y-auto border border-[#2a2a2a] bg-[#1a1a1a]">
            {suggestionMatches.map((suggestion) => (
              <button
                key={suggestion.command}
                className={`flex w-full items-center justify-between px-4 py-2 text-left text-sm font-mono transition-colors hover:bg-[#232323] ${
                  suggestionMatches[activeSuggestionIndex]?.command === suggestion.command
                    ? 'bg-[#232323]'
                    : ''
                }`}
                onClick={() => activateSuggestion(suggestion.command)}
                type="button"
              >
                <span className="text-[#58a6ff]">{suggestion.command}</span>
                <span className="ml-4 text-[11px] text-[#888888]">{suggestion.description}</span>
              </button>
            ))}
          </div>
        ) : null}

        <div className="min-w-0 border border-[#2a2a2a] bg-[#1a1a1a] px-4 py-3 transition-all focus-within:border-[#58a6ff]">
          <div className="flex min-w-0 items-center gap-2">
            <span className="select-none font-mono text-lg text-[#58a6ff]">{'>'}</span>
            <input
              ref={inputRef}
              type="text"
              value={input}
              onChange={handleInputChange}
              onKeyDown={handleKeyDown}
              placeholder={
                actionComposerActive
                  ? 'Or type a raw command directly...'
                  : placeholder
              }
              disabled={isProcessing}
              className="min-w-0 flex-1 bg-transparent text-[15px] text-[#e0e0e0] outline-none placeholder:text-[#888888] disabled:opacity-50"
            />

            {isProcessing ? (
              <div className="flex items-center gap-1">
                <span className="h-2 w-2 animate-pulse rounded-full bg-[#58a6ff]" />
                <span className="h-2 w-2 animate-pulse rounded-full bg-[#58a6ff] delay-75" />
                <span className="h-2 w-2 animate-pulse rounded-full bg-[#58a6ff] delay-150" />
              </div>
            ) : input ? (
              <span className="select-none text-xs font-mono text-[#888888]">↵</span>
            ) : null}
          </div>
        </div>

        <div className="mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-[11px] font-mono text-[#888888]">
          <span>↑/↓ suggestions</span>
          <span>Tab autocomplete</span>
          <span>Ctrl+L clear</span>
          <span className="text-[#666666]">{helperText}</span>
        </div>
      </div>
    );
  },
);

CommandInput.displayName = 'CommandInput';
