'use client'

import { ChangeEvent, forwardRef, HTMLProps, ReactNode } from 'react'

import type { IPktSearchInputSuggestion } from 'shared-types/searchinput'

import { useFocusModality } from '../../hooks/useFocusModality'
import { PktButton } from '../button/Button'

/**
 * React suggestion item: portable fields from {@link IPktSearchInputSuggestion}
 * plus optional rich content and per-row handler.
 */
export type PktSearchInputSuggestion = Omit<IPktSearchInputSuggestion, 'title' | 'text'> & {
  title?: string | ReactNode
  text?: string | ReactNode
  onClick?: () => void
}

interface ISearch extends HTMLProps<HTMLInputElement> {
  appearance?: 'local' | 'local-with-button' | 'global'
  inputSize?: 'small' | 'medium' | 'xsmall'
  disabled?: boolean
  fullwidth?: boolean
  id: string
  label?: string
  name?: string
  placeholder?: string
  suggestions?: PktSearchInputSuggestion[]
  value?: string | undefined
  onSearch?: (value: string) => void
  onSuggestionClick?: (index: number) => void
  action?: string
  method?: 'get' | 'post' | 'dialog'
}

interface ISearchForm extends ISearch {
  action?: string
  method?: 'get' | 'post' | 'dialog'
}

interface ISearchInput extends ISearch {
  onChange: (event: ChangeEvent<HTMLInputElement>) => void
  disabled?: boolean
}

export const PktSearchInput = forwardRef<HTMLInputElement, ISearchInput | ISearchForm>(
  (
    {
      appearance = 'local',
      inputSize = 'medium',
      disabled = false,
      fullwidth = false,
      id,
      label,
      name,
      placeholder = 'Søk…',
      suggestions,
      value = '',
      action,
      method,
      onChange,
      onSearch,
      onSuggestionClick,
      ...props
    },
    ref,
  ) => {
    const handleSuggestionActivate = (cb: (() => void) | undefined, index: number) => {
      if (cb) {
        cb()
      } else if (onSuggestionClick) {
        onSuggestionClick(index)
      }
    }

    const handleNoOnChange = (e: ChangeEvent<HTMLInputElement>) => {
      value = e.target.value
    }

    const wrapperClass = [
      'pkt-searchinput',
      `pkt-searchinput--${appearance}`,
      `pkt-searchinput--${inputSize}`,
      fullwidth && 'pkt-searchinput--fullwidth',
    ]
      .filter(Boolean)
      .join(' ')

    const focusModality = useFocusModality()

    const wrapperProps = {
      role: 'search',
      className: wrapperClass,
      ...focusModality,
    }

    const WrapperElement = (children: ReactNode) =>
      action ? (
        <form {...wrapperProps} action={action} method={method}>
          {children}
        </form>
      ) : (
        <div {...wrapperProps}>{children}</div>
      )

    const suggestionContent = (suggestion: PktSearchInputSuggestion) => (
      <>
        {suggestion.title && <h3 className="pkt-searchinput__suggestion-title">{suggestion.title}</h3>}
        {suggestion.text && <p className="pkt-searchinput__suggestion-text">{suggestion.text}</p>}
      </>
    )

    const suggestionClassName = (suggestion: PktSearchInputSuggestion) =>
      ['pkt-searchinput__suggestion', suggestion.onClick ? 'pkt-link-button' : ''].filter(Boolean).join(' ')

    const fieldClass =
      appearance === 'local' ? `pkt-input__container pkt-input__container--${inputSize}` : 'pkt-searchinput__field'

    return WrapperElement(
      <>
        {label && (
          <label htmlFor={label ? id : undefined} className={label ? 'pkt-inputwrapper__label' : ''}>
            {label}
          </label>
        )}
        <div className={fieldClass}>
          <input
            className={`pkt-input pkt-input--${inputSize} ${fullwidth ? 'pkt-input--fullwidth' : ''}`}
            type="search"
            name={name || id}
            id={id}
            placeholder={placeholder}
            defaultValue={value}
            disabled={disabled}
            autoComplete="off"
            aria-autocomplete={suggestions ? 'list' : undefined}
            ref={ref}
            aria-controls={suggestions ? `${id}-suggestions` : undefined}
            onChange={onChange ? onChange : handleNoOnChange}
            onKeyUp={
              onSearch &&
              ((event) => {
                if (event.key === 'Enter') {
                  event.preventDefault()
                  onSearch(value)
                }
              })
            }
            {...props}
          />

          <PktButton
            className={`pkt-searchinput__button ${appearance === 'local' ? 'pkt-input-icon' : ''}`}
            variant="icon-only"
            iconName="magnifying-glass-big"
            size={inputSize}
            skin={appearance === 'local' ? 'tertiary' : 'primary'}
            color={appearance === 'global' ? 'yellow' : undefined}
            type="submit"
            disabled={disabled}
            onClick={
              onSearch &&
              ((event) => {
                event.preventDefault()
                onSearch(value)
              })
            }
          >
            {label || placeholder}
          </PktButton>
        </div>

        {suggestions && (
          <ul id={`${id}-suggestions`} className="pkt-searchinput__suggestions" aria-live="assertive">
            {suggestions.map((suggestion, index) =>
              suggestion.href ? (
                <li key={`search-suggestion-${index}`}>
                  <a
                    href={suggestion.href}
                    className={suggestionClassName(suggestion)}
                    onClick={() => handleSuggestionActivate(suggestion.onClick, index)}
                  >
                    {suggestionContent(suggestion)}
                  </a>
                </li>
              ) : suggestion.nonInteractive ? (
                <li key={`search-suggestion-${index}`}>
                  <div className="pkt-searchinput__suggestion">{suggestionContent(suggestion)}</div>
                </li>
              ) : (
                <li key={`search-suggestion-${index}`}>
                  <button
                    type="button"
                    className={suggestionClassName(suggestion)}
                    onClick={() => handleSuggestionActivate(suggestion.onClick, index)}
                  >
                    {suggestionContent(suggestion)}
                  </button>
                </li>
              ),
            )}
          </ul>
        )}
      </>,
    )
  },
)

PktSearchInput.displayName = 'PktSearchInput'
