import {
  forwardRef,
  useImperativeHandle,
  useRef,
  type CSSProperties,
  type FormEvent,
  type KeyboardEvent,
  type ReactNode,
} from 'react';

export interface PromptComposerProps {
  /** Controlled input value. */
  value: string;
  /** Standard onChange — accepts the Vercel-AI-SDK-shaped event. */
  onChange: (e: { target: { value: string } }) => void;
  /** Called on Enter (without Shift) or send-button click. */
  onSubmit: (e?: { preventDefault?: () => void }) => void | Promise<void>;
  /** Disable input + submit (e.g. while streaming). */
  disabled?: boolean;
  /** Placeholder when empty. */
  placeholder?: string;
  /** Render a Stop button instead of Send (e.g. during streaming). */
  showStop?: boolean;
  /** Called when the Stop button is clicked. */
  onStop?: () => void;
  /** Auto-grow up to this many lines before scrolling. Default 8. */
  maxLines?: number;
  /** Extra controls rendered to the left of the send button. */
  leadingActions?: ReactNode;
  /** Tailwind escape hatch. */
  className?: string;
  /** Inline style escape hatch. */
  style?: CSSProperties;
  /** ARIA label for the textarea. */
  ariaLabel?: string;
}

export interface PromptComposerHandle {
  focus: () => void;
  clear: () => void;
}

/**
 * Multi-line prompt input with submit-on-Enter + Shift-Enter newline,
 * auto-growing textarea, optional Stop affordance during streaming, and
 * slots for slash-commands or other leading actions (Wave 2 extension).
 *
 * Keyboard:
 *   Enter           — submit
 *   Shift+Enter     — newline
 *   Cmd/Ctrl+Enter  — submit (alternate; useful when textarea grows)
 *   Escape          — blur
 */
export const PromptComposer = forwardRef<PromptComposerHandle, PromptComposerProps>(
  function PromptComposer(
    {
      value,
      onChange,
      onSubmit,
      disabled = false,
      placeholder = 'Send a message…',
      showStop = false,
      onStop,
      maxLines = 8,
      leadingActions,
      className,
      style,
      ariaLabel = 'Message',
    },
    ref,
  ) {
    const textareaRef = useRef<HTMLTextAreaElement>(null);

    useImperativeHandle(
      ref,
      () => ({
        focus: () => textareaRef.current?.focus(),
        clear: () => {
          onChange({ target: { value: '' } });
          textareaRef.current?.focus();
        },
      }),
      [onChange],
    );

    const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key === 'Escape') {
        e.currentTarget.blur();
        return;
      }
      const isCmdEnter = (e.metaKey || e.ctrlKey) && e.key === 'Enter';
      const isPlainEnter = e.key === 'Enter' && !e.shiftKey && !e.metaKey && !e.ctrlKey;
      if ((isPlainEnter || isCmdEnter) && !disabled && value.trim()) {
        e.preventDefault();
        void onSubmit({ preventDefault: () => undefined });
      }
    };

    const handleFormSubmit = (e: FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      if (!disabled && value.trim()) void onSubmit(e);
    };

    // Compute auto-grow height — line-height (1.5) × maxLines, capped.
    const maxHeight = `calc(1.5em * ${maxLines} + var(--bl-space-3, 12px) * 2)`;

    return (
      <form
        data-testid="bl-prompt-composer"
        onSubmit={handleFormSubmit}
        className={className}
        style={{
          display: 'flex',
          alignItems: 'flex-end',
          gap: 'var(--bl-space-2, 8px)',
          padding: 'var(--bl-space-2, 8px)',
          border: '1px solid var(--bl-border, rgba(0,0,0,0.12))',
          borderRadius: 'var(--bl-radius-card, 12px)',
          background: 'var(--bl-surface-card, #fff)',
          ...style,
        }}
      >
        {leadingActions && (
          <div
            data-testid="bl-prompt-leading"
            style={{ display: 'flex', alignItems: 'center', gap: 'var(--bl-space-1, 4px)' }}
          >
            {leadingActions}
          </div>
        )}

        <textarea
          ref={textareaRef}
          data-testid="bl-prompt-textarea"
          aria-label={ariaLabel}
          value={value}
          placeholder={placeholder}
          disabled={disabled}
          rows={1}
          onChange={onChange}
          onKeyDown={handleKeyDown}
          // Auto-grow: reset, then expand to scrollHeight on each keystroke.
          onInput={e => {
            const ta = e.currentTarget;
            ta.style.height = 'auto';
            ta.style.height = `${ta.scrollHeight}px`;
          }}
          style={{
            flex: 1,
            resize: 'none',
            border: 'none',
            outline: 'none',
            background: 'transparent',
            color: 'var(--bl-text-primary, inherit)',
            fontFamily: 'inherit',
            fontSize: '0.95rem',
            lineHeight: 1.5,
            padding: 'var(--bl-space-2, 8px)',
            maxHeight,
            overflowY: 'auto',
          }}
        />

        {showStop ? (
          <button
            type="button"
            data-testid="bl-prompt-stop"
            onClick={() => onStop?.()}
            aria-label="Stop generating"
            style={sendButtonStyle('var(--bl-danger, #ef4444)')}
          >
            ◼
          </button>
        ) : (
          <button
            type="submit"
            data-testid="bl-prompt-send"
            disabled={disabled || !value.trim()}
            aria-label="Send message"
            style={{
              ...sendButtonStyle('var(--bl-accent, #6366f1)'),
              opacity: disabled || !value.trim() ? 0.4 : 1,
              cursor: disabled || !value.trim() ? 'not-allowed' : 'pointer',
            }}
          >
            ↑
          </button>
        )}
      </form>
    );
  },
);

function sendButtonStyle(bg: string): CSSProperties {
  return {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    width: 36,
    height: 36,
    border: 'none',
    borderRadius: 'var(--bl-radius-pill, 999px)',
    background: bg,
    color: 'var(--bl-accent-foreground, #fff)',
    fontSize: 16,
    cursor: 'pointer',
    transition: 'transform 80ms ease-out, opacity 120ms ease-out',
  };
}
