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 {
  workspaceId: string;
  value: string;
  onValueChange: (value: string) => void;
  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>(
  (
    {
      workspaceId,
      value,
      onValueChange,
      onSubmit,
      onStartPortfolioAction,
      onUpdatePortfolioDraft,
      onClearPortfolioAction,
      isProcessing,
      resetCommandIndex,
      portfolioMode,
      activePortfolioAction,
      portfolioDraft,
      lastPortfolioCommand,
      placeholder = 'Type command or natural language query...',
    },
    ref,
  ) => {
    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(value)),
      [actionComposerActive, value],
    );

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

    useEffect(() => {
      setShowSuggestions(value.startsWith('/'));
      setActiveSuggestionIndex(0);
      setShadowCollapsed(false);
    }, [value, workspaceId]);

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

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

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

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

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

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

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

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

      onValueChange(`${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>) => {
      onValueChange(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.';

    const shouldShowSuggestions = !actionComposerActive && showSuggestions && suggestionMatches.length > 0;

    return (
      <div className="relative min-w-0">
        {actionComposerActive && actionMeta ? (
          <div className="mb-3 overflow-hidden rounded-2xl border border-term-border bg-term-elevated shadow-[0_16px_40px_rgba(0,0,0,0.18)]">
            <div className="flex items-center justify-between border-b border-term-border-subtle bg-term-surface px-4 py-2">
              <div className="text-xs font-mono text-term-text">
                {ACTION_LABELS[activePortfolioAction]}
              </div>
              <button
                type="button"
                onClick={onClearPortfolioAction}
                className="text-[11px] font-mono text-term-text-tertiary transition-colors hover:text-term-text"
              >
                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-term-text-tertiary">
                    <span>Symbol</span>
                    <input
                      ref={actionPrimaryFieldRef}
                      type="text"
                      value={portfolioDraft.symbol}
                      onChange={(event) =>
                        onUpdatePortfolioDraft({ symbol: event.target.value.toUpperCase() })
                      }
                      disabled={isProcessing}
                      className="border border-term-border bg-term-bg px-3 py-2 text-sm text-term-text outline-none transition-colors focus:border-info"
                    />
                  </label>
                  <label className="flex flex-col gap-1 text-[11px] font-mono text-term-text-tertiary">
                    <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-term-border bg-term-bg px-3 py-2 text-sm text-term-text outline-none transition-colors focus:border-info"
                    />
                  </label>
                  <label className="flex flex-col gap-1 text-[11px] font-mono text-term-text-tertiary">
                    <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-term-border bg-term-bg px-3 py-2 text-sm text-term-text outline-none transition-colors focus:border-info"
                    />
                  </label>
                </>
              )}

              {(activePortfolioAction === 'deposit' || activePortfolioAction === 'withdraw') && (
                <label className="flex flex-col gap-1 text-[11px] font-mono text-term-text-tertiary 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-term-border bg-term-bg px-3 py-2 text-sm text-term-text outline-none transition-colors focus:border-info"
                  />
                </label>
              )}
            </div>

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

        <div className="relative">
          <div className="min-w-0 rounded-2xl border border-term-border bg-term-highlight px-4 py-3 shadow-[0_12px_30px_rgba(0,0,0,0.14)] transition-all focus-within:border-info focus-within:shadow-[0_0_0_1px_rgba(127,212,201,0.24)]">
            <div className="flex min-w-0 items-center gap-2">
              <span className="select-none font-mono text-lg text-info">{'>'}</span>
              <input
                ref={inputRef}
                type="text"
                value={value}
                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-term-text outline-none placeholder:text-term-text-tertiary disabled:opacity-50"
              />

              {isProcessing ? (
                <div className="flex items-center gap-1">
                  <span className="h-2 w-2 animate-pulse rounded-full bg-info" />
                  <span className="h-2 w-2 animate-pulse rounded-full bg-info delay-75" />
                  <span className="h-2 w-2 animate-pulse rounded-full bg-info delay-150" />
                </div>
              ) : value ? (
                <span className="select-none text-xs font-mono text-term-text-tertiary">↵</span>
              ) : null}
            </div>
          </div>

          {shouldShowSuggestions ? (
            <div className="mt-3 overflow-hidden rounded-2xl border border-term-border bg-term-elevated shadow-[0_24px_60px_rgba(0,0,0,0.24)]">
              <div className="flex items-center justify-between border-b border-term-border-subtle bg-term-surface px-4 py-2">
                <span className="text-[10px] font-mono uppercase tracking-[0.2em] text-term-text-muted">
                  Autocomplete
                </span>
                <span className="text-[10px] font-mono text-term-text-tertiary">
                  {suggestionMatches.length} match{suggestionMatches.length === 1 ? '' : 'es'}
                </span>
              </div>
              <div className="max-h-[280px] overflow-y-auto">
                {suggestionMatches.map((suggestion, index) => {
                  const isActive = suggestionMatches[activeSuggestionIndex]?.command === suggestion.command;
                  return (
                    <button
                      key={suggestion.command}
                      className={`flex w-full flex-col items-start gap-1 border-b border-term-border-subtle px-4 py-3 text-left font-mono transition-colors last:border-b-0 ${
                        isActive ? 'bg-info/10' : 'hover:bg-term-surface'
                      }`}
                      onClick={() => activateSuggestion(suggestion.command)}
                      type="button"
                    >
                      <div className="flex w-full items-center justify-between gap-3">
                        <span className={`text-sm ${isActive ? 'text-term-text' : 'text-info'}`}>
                          {suggestion.command}
                        </span>
                        <span
                          className={`rounded-full border px-2 py-0.5 text-[10px] uppercase tracking-[0.16em] ${
                            isActive
                              ? 'border-info/50 bg-term-bg text-info'
                              : 'border-term-border bg-term-bg text-term-text-tertiary'
                          }`}
                        >
                          {index + 1}
                        </span>
                      </div>
                      <span className="text-[11px] leading-5 text-term-text-muted">
                        {suggestion.description}
                      </span>
                    </button>
                  );
                })}
              </div>
            </div>
          ) : null}
        </div>

        {!actionComposerActive && shadowState ? (
          <div className="mt-3 overflow-visible rounded-2xl border border-term-border bg-term-elevated shadow-[0_20px_50px_rgba(0,0,0,0.22)]">
            <div className="flex items-center justify-between border-b border-term-border-subtle bg-term-surface px-3 py-2">
              <span className="text-[9px] font-mono uppercase tracking-wider text-term-text-muted">
                Command Shadow
              </span>
              <div className="flex items-center gap-2">
                <span
                  className={`text-[9px] font-mono ${
                    shadowState.readyToRun && !shadowState.hasExtraInput
                      ? 'text-positive'
                      : shadowState.mode === 'predictive'
                        ? 'text-info'
                        : 'text-term-text-tertiary'
                  }`}
                >
                  {shadowState.readyToRun && !shadowState.hasExtraInput
                    ? 'Ready'
                    : shadowState.mode === 'predictive'
                      ? 'Autocomplete'
                      : 'Fill Parameters'}
                </span>
                <button
                  type="button"
                  onClick={() => setShadowCollapsed(!shadowCollapsed)}
                  className="rounded-md p-1 text-term-text-tertiary transition-colors hover:bg-term-highlight hover:text-term-text"
                >
                  {shadowCollapsed ? (
                    <ChevronDown className="h-3 w-3" />
                  ) : (
                    <ChevronUp className="h-3 w-3" />
                  )}
                </button>
              </div>
            </div>

            {!shadowCollapsed && (
              <>
                <div className="border-b border-term-border-subtle px-3 py-2">
                  <code className="text-xs font-mono text-term-text">
                    {shadowState.signature}
                  </code>
                </div>

                <div className="px-3 py-3">
                  {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={`rounded-lg border px-2.5 py-1.5 text-[10px] font-mono transition-colors ${
                            argument.isActive
                              ? 'border-info/60 bg-info/10 text-term-text shadow-[inset_0_0_0_1px_rgba(127,212,201,0.18)]'
                              : argument.isFilled
                                ? 'border-positive/30 bg-positive/10 text-positive'
                                : 'border-term-border bg-term-surface text-term-text-muted'
                          }`}
                        >
                          <span className="text-term-text-tertiary">{index + 1}.</span> {argument.spec.label}
                          {argument.spec.required && (
                            <span className="ml-1 text-warning">*</span>
                          )}
                        </div>
                      ))}
                    </div>
                  ) : (
                    <span className="text-[10px] font-mono text-term-text-muted">
                      No parameters required
                    </span>
                  )}
                </div>

                {shadowState.spec.examples?.length && shadowState.spec.examples.length > 0 && (
                  <div className="border-t border-term-border-subtle bg-term-surface/40 px-3 py-2.5">
                    <div className="flex flex-wrap gap-1.5">
                      {shadowState.spec.examples.slice(0, 3).map((example) => (
                        <button
                          key={example}
                          type="button"
                          onClick={() => {
                            onValueChange(example);
                            setShowSuggestions(false);
                            setActiveSuggestionIndex(0);
                            resetCommandIndex();
                            inputRef.current?.focus();
                          }}
                          className="rounded-md border border-term-border bg-term-bg px-2 py-1 text-[9px] font-mono text-term-text-tertiary transition-colors hover:border-info hover:text-term-text"
                        >
                          {example}
                        </button>
                      ))}
                      {shadowState.spec.examples.length > 3 && (
                        <span className="text-[9px] font-mono text-term-text-muted">
                          +{shadowState.spec.examples.length - 3} more
                        </span>
                      )}
                    </div>
                  </div>
                )}
              </>
            )}
          </div>
        ) : null}

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

CommandInput.displayName = 'CommandInput';
