import { useEffect, useMemo, useRef, useState } from 'react'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import CircularProgress from '@mui/material/CircularProgress'
import List from '@mui/material/List'
import ListItemButton from '@mui/material/ListItemButton'
import ListItemText from '@mui/material/ListItemText'
import Stack from '@mui/material/Stack'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import { reverseGeocode, searchPlaces } from '../api/map-geocoding'
import { MapPickerMap } from './MapPickerMap'
import type { LatLng, NominatimItem } from '../model/types'

export function AddressMapPicker(props: {
  value: { lat: number; lng: number } | null
  onChange: (v: { lat: number; lng: number; addressLine?: string | null }) => void
}) {
  const { value, onChange } = props
  const [q, setQ] = useState('')
  const [searching, setSearching] = useState(false)
  const [results, setResults] = useState<NominatimItem[]>([])
  const [hint, setHint] = useState<string | null>(null)
  const abortRef = useRef<AbortController | null>(null)
  const lastQueryRef = useRef<string>('')
  const lastRequestAtRef = useRef<number>(0)

  const qTrimmed = q.trim()
  const visibleResults = qTrimmed.length >= 3 ? results : []

  const center = useMemo(() => {
    if (value) return { lat: value.lat, lng: value.lng }
    return { lat: 55.751244, lng: 37.618423 }
  }, [value])

  const pick = async (pos: LatLng) => {
    setHint(null)
    onChange({ lat: pos.lat, lng: pos.lng })
    try {
      const addr = await reverseGeocode(pos)
      if (addr) {
        setHint(addr)
        onChange({ lat: pos.lat, lng: pos.lng, addressLine: addr })
      }
    } catch {
      // ignore
    }
  }

  useEffect(() => {
    const s = qTrimmed
    if (s.length < 3) {
      return
    }

    const t = window.setTimeout(async () => {
      const now = Date.now()
      if (now - lastRequestAtRef.current < 900) return
      if (s === lastQueryRef.current) return

      lastQueryRef.current = s
      lastRequestAtRef.current = now

      abortRef.current?.abort()
      const ac = new AbortController()
      abortRef.current = ac

      setSearching(true)
      try {
        setResults(await searchPlaces(s, ac.signal))
      } catch (e) {
        if ((e as { name?: string })?.name !== 'AbortError') {
          setResults([])
        }
      } finally {
        setSearching(false)
      }
    }, 450)

    return () => {
      window.clearTimeout(t)
    }
  }, [qTrimmed])

  return (
    <Stack spacing={1.5}>
      <Typography variant="subtitle2">Выбор на карте</Typography>

      <Stack direction={{ xs: 'column', sm: 'row' }} spacing={1.5}>
        <TextField size="small" label="Найти адрес" value={q} onChange={(e) => setQ(e.target.value)} fullWidth />
        <Button
          variant="outlined"
          onClick={async () => {
            const s = q.trim()
            if (!s) return
            abortRef.current?.abort()
            const ac = new AbortController()
            abortRef.current = ac
            setSearching(true)
            try {
              lastQueryRef.current = s
              lastRequestAtRef.current = Date.now()
              setResults(await searchPlaces(s, ac.signal))
            } finally {
              setSearching(false)
            }
          }}
          disabled={searching || !q.trim()}
          sx={{ minWidth: 160 }}
        >
          {searching ? <CircularProgress size={18} /> : 'Найти'}
        </Button>
      </Stack>

      {visibleResults.length > 0 && (
        <List dense sx={{ border: 1, borderColor: 'divider', borderRadius: 2 }}>
          {visibleResults.map((r) => (
            <ListItemButton
              key={`${r.lat}:${r.lon}:${r.display_name}`}
              onClick={() => {
                const lat = Number(r.lat)
                const lng = Number(r.lon)
                if (!Number.isFinite(lat) || !Number.isFinite(lng)) return
                void pick({ lat, lng })
              }}
            >
              <ListItemText primary={r.display_name} />
            </ListItemButton>
          ))}
        </List>
      )}

      <MapPickerMap value={value} onChange={onChange} center={center} />

      <Box sx={{ minHeight: 32, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
        {hint && (
          <Typography variant="caption" color="text.secondary">
            Подсказка адреса: {hint}
          </Typography>
        )}
      </Box>
    </Stack>
  )
}
