import { useMemo } from 'react'
import type { ReactNode } from 'react'

interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label?: string
  error?: string
  helperText?: string
  leftIcon?: ReactNode
  rightIcon?: ReactNode
}

function generateId(prefix: string, providedId?: string): string {
  if (providedId) {
    return providedId
  }
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 5)}`
}

function getErrorClasses(error: string | undefined): string {
  if (!error) {
    return ''
  }
  return 'border-red-500/50 focus:border-red-500 focus:ring-red-500/50'
}

function getInputClasses(params: {
  error: string | undefined
  leftIcon: ReactNode | undefined
  rightIcon: ReactNode | undefined
  className: string
}): string {
  const baseClasses = 'block w-full px-3 py-2 border rounded-lg bg-cyber-dark text-cyber-accent placeholder-cyber-accent/50 focus:outline-none focus:ring-2 focus:ring-neon-cyan focus:border-neon-cyan transition-colors'
  const errorClasses = getErrorClasses(params.error)
  const paddingLeft = params.leftIcon ? 'pl-10' : ''
  const paddingRight = params.rightIcon ? 'pr-10' : ''
  return `${baseClasses} ${errorClasses} ${paddingLeft} ${paddingRight} ${params.className}`.trim()
}

function getAriaDescribedBy(inputId: string, error: string | undefined, helperText: string | undefined): string | undefined {
  if (error) {
    return `${inputId}-error`
  }
  if (helperText) {
    return `${inputId}-helper`
  }
  return undefined
}

function InputLabel({ inputId, label }: { inputId: string; label: string }): React.ReactElement {
  return (
    <label htmlFor={inputId} className="block text-sm font-medium text-cyber-accent mb-1">
      {label}
    </label>
  )
}

function InputIcons({ leftIcon, rightIcon }: { leftIcon?: ReactNode; rightIcon?: ReactNode }): React.ReactElement | null {
  if (!leftIcon && !rightIcon) {
    return null
  }
  return (
    <>
      {leftIcon && (
        <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-cyber-accent/50">
          {leftIcon}
        </div>
      )}
      {rightIcon && (
        <div className="absolute inset-y-0 right-0 pr-3 flex items-center text-cyber-accent/50">
          {rightIcon}
        </div>
      )}
    </>
  )
}

function InputError({ inputId, error }: { inputId: string; error: string }): React.ReactElement {
  return (
    <p id={`${inputId}-error`} className="mt-1 text-sm text-red-400" role="alert">
      {error}
    </p>
  )
}

function InputHelper({ inputId, helperText }: { inputId: string; helperText: string }): React.ReactElement {
  return (
    <p id={`${inputId}-helper`} className="mt-1 text-sm text-cyber-accent/70">
      {helperText}
    </p>
  )
}

export function Input({
  label,
  error,
  helperText,
  leftIcon,
  rightIcon,
  className = '',
  id,
  ...props
}: InputProps): React.ReactElement {
  const inputId = useMemo(() => generateId('input', id), [id])
  const inputClasses = useMemo(
    () => getInputClasses({ error, leftIcon, rightIcon, className }),
    [error, leftIcon, rightIcon, className]
  )
  const ariaDescribedBy = useMemo(() => getAriaDescribedBy(inputId, error, helperText), [inputId, error, helperText])

  return (
    <div className="w-full">
      {label && <InputLabel inputId={inputId} label={label} />}
      <div className="relative">
        <InputIcons leftIcon={leftIcon} rightIcon={rightIcon} />
        <input
          id={inputId}
          className={inputClasses}
          aria-invalid={error ? 'true' : 'false'}
          aria-describedby={ariaDescribedBy}
          {...props}
        />
      </div>
      {error && <InputError inputId={inputId} error={error} />}
      {helperText && !error && <InputHelper inputId={inputId} helperText={helperText} />}
    </div>
  )
}
