import React from 'react';
import { Alert, AlertIcon, Box, Link, Spinner, Text, VStack } from '@chakra-ui/react';
import ContactMap from '../home/ContactMap';
import { getPublicSettings } from '../../services/settings';

interface EventLocationMapProps {
  location: string;
  title?: string;
  latitude?: number | null;
  longitude?: number | null;
}

type GeocodeResult = {
  lat: number;
  lon: number;
  displayName: string;
};

const NOMINATIM_BASE_URL = process.env.REACT_APP_NOMINATIM_URL || 'https://nominatim.openstreetmap.org';
const NOMINATIM_EMAIL = process.env.REACT_APP_NOMINATIM_EMAIL;

const geocodeCache = new Map<string, GeocodeResult>();

async function geocodeLocation(query: string, signal: AbortSignal): Promise<GeocodeResult> {
  const cacheKey = query.trim().toLowerCase();
  if (geocodeCache.has(cacheKey)) {
    return geocodeCache.get(cacheKey)!;
  }

  const params = new URLSearchParams({
    format: 'jsonv2',
    limit: '1',
    q: query,
    'accept-language': 'cs',
  });

  if (NOMINATIM_EMAIL) {
    params.append('email', NOMINATIM_EMAIL);
  }

  const endpoint = `${NOMINATIM_BASE_URL}/search?${params.toString()}`;
  const response = await fetch(endpoint, {
    headers: { Accept: 'application/json' },
    signal,
  });

  if (!response.ok) {
    throw new Error('Nepodařilo se načíst mapová data.');
  }

  const json = await response.json();
  if (!Array.isArray(json) || json.length === 0) {
    throw new Error('Poloha nebyla nalezena.');
  }

  const first = json[0];
  const lat = Number(first.lat);
  const lon = Number(first.lon);

  if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
    throw new Error('Neplatné souřadnice.');
  }

  const result: GeocodeResult = {
    lat,
    lon,
    displayName: String(first.display_name || query),
  };
  geocodeCache.set(cacheKey, result);
  return result;
}

const EventLocationMap: React.FC<EventLocationMapProps> = ({ location, title, latitude, longitude }) => {
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [coords, setCoords] = React.useState<GeocodeResult | null>(null);
  const [settings, setSettings] = React.useState<any>(null);

  // Load settings for club colors
  React.useEffect(() => {
    getPublicSettings()
      .then(setSettings)
      .catch(() => {});
  }, []);

  React.useEffect(() => {
    const trimmed = (location || '').trim();
    if (!trimmed) {
      setCoords(null);
      setError(null);
      return;
    }

    // If coordinates are provided, use them directly
    if (latitude != null && longitude != null && Number.isFinite(latitude) && Number.isFinite(longitude)) {
      setCoords({
        lat: latitude,
        lon: longitude,
        displayName: trimmed,
      });
      setLoading(false);
      setError(null);
      return;
    }

    // Otherwise, geocode the location
    let active = true;
    const controller = new AbortController();
    setLoading(true);
    setError(null);

    geocodeLocation(trimmed, controller.signal)
      .then((result) => {
        if (!active) return;
        setCoords(result);
      })
      .catch((err: any) => {
        if (!active) return;
        setCoords(null);
        setError(err?.message || 'Mapu se nepodařilo načíst.');
      })
      .finally(() => {
        if (active) setLoading(false);
      });

    return () => {
      active = false;
      controller.abort();
    };
  }, [location, latitude, longitude]);

  if (!location?.trim()) {
    return null;
  }

  const openStreetMapUrl = `https://www.openstreetmap.org/search?query=${encodeURIComponent(location.trim())}`;

  return (
    <VStack align="stretch" spacing={3} mt={4} data-testid="event-location-map">
      <Text fontWeight="semibold" fontSize="lg">Mapa místa</Text>

      {loading && (
        <HStackWithSpinner />
      )}

      {!loading && error && (
        <Alert status="error" borderRadius="md">
          <AlertIcon />
          <Box>
            <Text mb={1}>{error}</Text>
            <Link href={openStreetMapUrl} isExternal color="blue.400">
              Otevřít v OpenStreetMap
            </Link>
          </Box>
        </Alert>
      )}

      {!loading && !error && coords && (
        <Box borderWidth="1px" borderRadius="lg" overflow="hidden" borderColor="border.subtle">
          <ContactMap
            latitude={coords.lat}
            longitude={coords.lon}
            zoom={15}
            address={coords.displayName}
            clubName={title}
            height={320}
            mapStyle={settings?.map_style || 'default'}
            clubPrimaryColor={settings?.primary_color}
            clubSecondaryColor={settings?.accent_color}
          />
        </Box>
      )}

      <Text fontSize="sm" color="gray.500">
        Přesnost určena pomocí otevřených mapových dat.{' '}
        <Link href={openStreetMapUrl} isExternal color="blue.400">
          Zobrazit v OpenStreetMap
        </Link>
      </Text>
    </VStack>
  );
};

const HStackWithSpinner: React.FC = () => (
  <Box display="flex" alignItems="center" gap={2} color="gray.500">
    <Spinner size="sm" />
    <Text>Načítám mapu…</Text>
  </Box>
);

export default EventLocationMap;
