import React, { FC, useCallback, useMemo } from 'react'
import { HsCode } from '../model/models'
import apiFetch from '@wordpress/api-fetch'
import { ComboboxControl } from '@wordpress/components'
import { useI18n } from '@wordpress/react-i18n'

export declare interface HsCodeSelectorProps {
  value: string | null | undefined
  onSelectHsCode: (hsCode: string | null | undefined) => void
}

const HsCodeSelector: FC<HsCodeSelectorProps> = ({ value, onSelectHsCode }) => {
  const { __ } = useI18n()
  const [loading, setLoading] = React.useState<boolean>(false)
  const [hsCodes, setHsCodes] = React.useState<Array<HsCode>>([])
  const [filterQuery, setFilterQuery] = React.useState<string>('')

  const getHsCodes = useCallback(async (query: string) => {
    if (!query.trim()) {
      setFilterQuery('')
      setHsCodes([])
      return
    }
    setFilterQuery(query)
    setLoading(true)

    try {
      const response = await apiFetch<Array<HsCode>>({
        path: `/posten-bring-checkout/hscodes?q=${encodeURIComponent(query)}`,
      })
      setHsCodes(response ?? [])
    } catch {
      setHsCodes([])
    } finally {
      setLoading(false)
    }
  }, [])

  const debouncedGetHsCodes = useMemo(() => {
    let timeout: ReturnType<typeof setTimeout>

    return (query: string) => {
      clearTimeout(timeout)

      timeout = setTimeout(() => {
        getHsCodes(query)
      }, 300)
    }
  }, [getHsCodes])

  const escapeRegExp = useCallback(
    (val: string) => val.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'),
    []
  )

  const highlightMatch = useCallback(
    (label: string, query: string) => {
      if (!query.trim()) {
        return label
      }

      const regex = new RegExp(`(${escapeRegExp(query.trim())})`, 'i')

      return (
        label
          .split(regex)
          .map((part, index) =>
            regex.test(part) ? (
              <mark key={index}>{part}</mark>
            ) : (
              <span key={index}>{part}</span>
            )
          ) ?? label
      )
    },
    [escapeRegExp]
  )

  return (
    <ComboboxControl
      label={__('Harmonized system code (HS code)', 'posten-bring-checkout')}
      hideLabelFromVision={false}
      __next40pxDefaultSize={true}
      __experimentalRenderItem={option => (
        <div className="flex flex-dir-col gaxs">
          <span className="hs-code">
            {option.item.value.match(/.{1,2}/g)?.join('.')}
          </span>
          <span>
            {highlightMatch(
              option.item.label.replace(/^\d{2}(?:\.\d{2})+\s*-\s*/, ''),
              filterQuery
            )}
          </span>
        </div>
      )}
      placeholder={__(
        'Enter a 6-digit HS code, or search by item type (at least 3 characters required)',
        'posten-bring-checkout'
      )}
      className="mtm hs-codes"
      options={hsCodes.map(hsCode => ({
        value: hsCode.code,
        label: `${hsCode.code.match(/.{1,2}/g)?.join('.')} - ${
          hsCode.description
        }`,
      }))}
      onFilterValueChange={debouncedGetHsCodes}
      value={value ?? ''}
      isLoading={loading}
      onChange={hsCode => {
        onSelectHsCode(hsCode)
      }}
    />
  )
}

export default HsCodeSelector
