'use client'

import { useEffect, useMemo, useState } from 'react'
import { X } from 'lucide-react'

interface LocationDropdownFieldProps {
  label: string
  placeholder: string
  hint: string
  addCustomLabel: (location: string) => string
  options: string[]
  value: string[]
  onChange: (locations: string[]) => void
}

const MAX_SUGGESTIONS = 8
const CUSTOM_LOCATION_OPTIONS_KEY = 'dashboard-custom-vehicle-location-options'
const CUSTOM_LOCATION_OPTIONS_CHANGED = 'dashboard-custom-vehicle-location-options-changed'

function normalizeLocationLabel(value: string) {
  return value.trim().replace(/\s+/g, ' ')
}

function normalizeSearchValue(value: string) {
  return normalizeLocationLabel(value)
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLocaleLowerCase()
}

function readCustomLocationOptions() {
  if (typeof window === 'undefined') return []

  try {
    const parsed = JSON.parse(window.localStorage.getItem(CUSTOM_LOCATION_OPTIONS_KEY) ?? '[]')
    if (!Array.isArray(parsed)) return []

    return parsed
      .map((entry) => (typeof entry === 'string' ? normalizeLocationLabel(entry) : ''))
      .filter(Boolean)
  } catch {
    return []
  }
}

function writeCustomLocationOptions(options: string[]) {
  if (typeof window === 'undefined') return
  window.localStorage.setItem(CUSTOM_LOCATION_OPTIONS_KEY, JSON.stringify(options))
  window.dispatchEvent(new Event(CUSTOM_LOCATION_OPTIONS_CHANGED))
}

export default function LocationDropdownField({
  label,
  placeholder,
  hint,
  addCustomLabel,
  options,
  value,
  onChange,
}: LocationDropdownFieldProps) {
  const [query, setQuery] = useState('')
  const [focused, setFocused] = useState(false)
  const [customOptions, setCustomOptions] = useState<string[]>([])
  const selected = value.map((location) => location.trim()).filter(Boolean)
  const selectedSet = new Set(selected.map(normalizeSearchValue))
  const allOptions = useMemo(() => {
    const seen = new Set<string>()
    return [...customOptions, ...options]
      .map(normalizeLocationLabel)
      .filter(Boolean)
      .filter((option) => {
        const key = normalizeSearchValue(option)
        if (seen.has(key)) return false
        seen.add(key)
        return true
      })
  }, [customOptions, options])
  const normalizedQuery = normalizeSearchValue(query)
  const suggestions = useMemo(() => {
    if (!normalizedQuery) return []

    return allOptions
      .filter((option) => !selectedSet.has(normalizeSearchValue(option)))
      .filter((option) => normalizeSearchValue(option).startsWith(normalizedQuery))
      .slice(0, MAX_SUGGESTIONS)
  }, [allOptions, normalizedQuery, selectedSet])
  const normalizedOptionSet = useMemo(() => {
    return new Set(allOptions.map(normalizeSearchValue))
  }, [allOptions])
  const typedLocation = normalizeLocationLabel(query)
  const canAddTypedLocation = Boolean(
    normalizedQuery &&
    !selectedSet.has(normalizedQuery) &&
    !normalizedOptionSet.has(normalizedQuery),
  )

  useEffect(() => {
    const syncCustomOptions = () => setCustomOptions(readCustomLocationOptions())

    syncCustomOptions()
    window.addEventListener('storage', syncCustomOptions)
    window.addEventListener(CUSTOM_LOCATION_OPTIONS_CHANGED, syncCustomOptions)

    return () => {
      window.removeEventListener('storage', syncCustomOptions)
      window.removeEventListener(CUSTOM_LOCATION_OPTIONS_CHANGED, syncCustomOptions)
    }
  }, [])

  const saveCustomLocation = (location: string) => {
    const normalizedLocation = normalizeLocationLabel(location)
    if (!normalizedLocation) return

    const existingOptions = readCustomLocationOptions()
    const existingKeys = new Set([...existingOptions, ...options].map(normalizeSearchValue))
    if (existingKeys.has(normalizeSearchValue(normalizedLocation))) return

    const nextOptions = [...existingOptions, normalizedLocation].sort((a, b) => a.localeCompare(b))
    writeCustomLocationOptions(nextOptions)
  }

  const addLocation = (location: string) => {
    const normalizedLocation = normalizeLocationLabel(location)
    if (!normalizedLocation || selectedSet.has(normalizeSearchValue(normalizedLocation))) return
    if (!normalizedOptionSet.has(normalizeSearchValue(normalizedLocation))) {
      saveCustomLocation(normalizedLocation)
    }
    onChange([...selected, normalizedLocation])
    setQuery('')
  }

  const removeLocation = (location: string) => {
    onChange(selected.filter((selectedLocation) => selectedLocation !== location))
  }

  const showSuggestions = focused && (suggestions.length > 0 || canAddTypedLocation)

  return (
    <div>
      <label className="block text-xs font-medium text-slate-500 mb-1.5">{label}</label>
      <div className="relative">
        <input
          type="text"
          className="input-field"
          placeholder={placeholder}
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onFocus={() => setFocused(true)}
          onBlur={() => setFocused(false)}
          onKeyDown={(e) => {
            if (e.key !== 'Enter') return
            if (suggestions[0]) {
              e.preventDefault()
              addLocation(suggestions[0])
              return
            }
            if (canAddTypedLocation) {
              e.preventDefault()
              addLocation(typedLocation)
            }
          }}
          aria-label={label}
          autoComplete="off"
        />
        {showSuggestions && (
          <div className="absolute z-20 mt-1 max-h-56 w-full overflow-y-auto rounded-lg border border-slate-200 bg-white py-1 shadow-lg">
            {suggestions.map((location) => (
              <button
                key={location}
                type="button"
                onMouseDown={(e) => {
                  e.preventDefault()
                  addLocation(location)
                }}
                className="block w-full px-3 py-2 text-left text-sm text-slate-700 transition hover:bg-slate-50 focus:bg-slate-50 focus:outline-none"
              >
                {location}
              </button>
            ))}
            {canAddTypedLocation && (
              <button
                type="button"
                onMouseDown={(e) => {
                  e.preventDefault()
                  addLocation(typedLocation)
                }}
                className="block w-full border-t border-slate-100 px-3 py-2 text-left text-sm font-medium text-blue-700 transition hover:bg-blue-50 focus:bg-blue-50 focus:outline-none"
              >
                {addCustomLabel(typedLocation)}
              </button>
            )}
          </div>
        )}
      </div>
      {selected.length > 0 && (
        <div className="mt-2 flex flex-wrap gap-2">
          {selected.map((location) => (
            <span key={location} className="inline-flex max-w-full items-center gap-1 rounded-full bg-white px-2.5 py-1 text-xs font-medium text-slate-700 ring-1 ring-slate-200">
              <span className="truncate">{location}</span>
              <button
                type="button"
                onClick={() => removeLocation(location)}
                className="rounded-full p-0.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700"
                aria-label={`Remove ${location}`}
              >
                <X className="h-3 w-3" />
              </button>
            </span>
          ))}
        </div>
      )}
      <p className="mt-1 text-xs text-slate-400">{hint}</p>
    </div>
  )
}
