import React from 'react'
import { renderPlaceholder } from '../hooks/renderPlaceholder.js'
import { usePasteHandler } from '../hooks/usePasteHandler.js'
import { useDeclaredCursor } from '../ink/hooks/use-declared-cursor.js'
import { Ansi, Box, Text, useInput } from '../ink.js'
import type {
  BaseInputState,
  BaseTextInputProps,
} from '../types/textInputTypes.js'
import type { TextHighlight } from '../utils/textHighlighting.js'
import { HighlightedInput } from './PromptInput/ShimmeredInput.js'

type BaseTextInputComponentProps = BaseTextInputProps & {
  inputState: BaseInputState
  children?: React.ReactNode
  terminalFocus: boolean
  highlights?: TextHighlight[]
  invert?: (text: string) => string
  hidePlaceholderText?: boolean
}

/**
 * A base component for text inputs that handles rendering and basic input
 */
export function BaseTextInput({
  inputState,
  children,
  terminalFocus,
  invert,
  hidePlaceholderText,
  ...props
}: BaseTextInputComponentProps): React.ReactNode {
  const { onInput, renderedValue, cursorLine, cursorColumn } = inputState

  // Park the native terminal cursor at the input caret. Terminal emulators
  // position IME preedit text at the physical cursor, and screen readers /
  // screen magnifiers track it — so parking here makes CJK input appear
  // inline and lets accessibility tools follow the input. The Box ref below
  // is the yoga layout origin; (cursorLine, cursorColumn) is relative to it.
  // Only active when the input is focused, showing its cursor, and the
  // terminal itself has focus.
  const cursorRef = useDeclaredCursor({
    line: cursorLine,
    column: cursorColumn,
    active: Boolean(props.focus && props.showCursor && terminalFocus),
  })

  const { wrappedOnInput, isPasting } = usePasteHandler({
    onPaste: props.onPaste,
    onInput: (input, key) => {
      // Prevent Enter key from triggering submission during paste
      if (isPasting && key.return) {
        return
      }
      onInput(input, key)
    },
    onImagePaste: props.onImagePaste,
  })

  // Notify parent when paste state changes
  const { onIsPastingChange } = props
  React.useEffect(() => {
    if (onIsPastingChange) {
      onIsPastingChange(isPasting)
    }
  }, [isPasting, onIsPastingChange])

  const { showPlaceholder, renderedPlaceholder } = renderPlaceholder({
    placeholder: props.placeholder,
    value: props.value,
    showCursor: props.showCursor,
    focus: props.focus,
    terminalFocus,
    invert,
    hidePlaceholderText,
  })

  useInput(wrappedOnInput, { isActive: props.focus })

  // Show argument hint only when we have a value and the hint is provided
  // Only show the argument hint when:
  // 1. We have a hint to show
  // 2. We have a command typed (value is not empty)
  // 3. The command doesn't have arguments yet (no text after the space)
  // 4. We're actually typing a command (the value starts with /)
  const commandWithoutArgs =
    (props.value && props.value.trim().indexOf(' ') === -1) ||
    (props.value && props.value.endsWith(' '))

  const showArgumentHint = Boolean(
    props.argumentHint &&
      props.value &&
      commandWithoutArgs &&
      props.value.startsWith('/'),
  )

  // Filter out highlights that contain the cursor position
  const cursorFiltered =
    props.showCursor && props.highlights
      ? props.highlights.filter(
          h =>
            h.dimColor ||
            props.cursorOffset < h.start ||
            props.cursorOffset >= h.end,
        )
      : props.highlights

  // Adjust highlights for viewport windowing: highlight positions reference the
  // full input text, but renderedValue only contains the windowed subset.
  const { viewportCharOffset, viewportCharEnd } = inputState
  const filteredHighlights =
    cursorFiltered && viewportCharOffset > 0
      ? cursorFiltered
          .filter(h => h.end > viewportCharOffset && h.start < viewportCharEnd)
          .map(h => ({
            ...h,
            start: Math.max(0, h.start - viewportCharOffset),
            end: h.end - viewportCharOffset,
          }))
      : cursorFiltered

  const hasHighlights = filteredHighlights && filteredHighlights.length > 0

  if (hasHighlights) {
    return (
      <Box ref={cursorRef}>
        <HighlightedInput
          text={renderedValue}
          highlights={filteredHighlights}
        />
        {showArgumentHint && (
          <Text dimColor>
            {props.value?.endsWith(' ') ? '' : ' '}
            {props.argumentHint}
          </Text>
        )}
        {children}
      </Box>
    )
  }

  return (
    <Box ref={cursorRef}>
      <Text wrap="truncate-end" dimColor={props.dimColor}>
        {showPlaceholder && props.placeholderElement ? (
          props.placeholderElement
        ) : showPlaceholder && renderedPlaceholder ? (
          <Ansi>{renderedPlaceholder}</Ansi>
        ) : (
          <Ansi>{renderedValue}</Ansi>
        )}
        {showArgumentHint && (
          <Text dimColor>
            {props.value?.endsWith(' ') ? '' : ' '}
            {props.argumentHint}
          </Text>
        )}
        {children}
      </Text>
    </Box>
  )
}
