// @design-system: domain/StoresMap
/**
 * StoresMap - Leaflet-powered map view for the stores directory.
 *
 * Both the Leaflet JS and its CSS are dynamically imported inside useEffect so
 * that neither ends up in the server Worker bundle (client:only island).
 */

'use client';

import { useEffect, useMemo, useRef, useState } from 'react';
import type { VendorCardData } from '@/components/ui/domain/VendorCard';
import { Skeleton } from '@/components/ui/feedback/Skeleton/Skeleton';
import { cn } from '@/lib/cn';
import { useT } from '@/lib/i18n/react';

export interface StoresMapProps {
  /** Vendors to render as map markers. Only vendors with lat/lng are shown. */
  vendors: VendorCardData[];
  /** Height CSS class - defaults to the stores map height token. */
  className?: string;
}

export function buildStorePopupContent(
  vendor: Pick<VendorCardData, 'id' | 'displayName' | 'city'>,
  linkLabel: string,
  colors: { muted: string; link: string },
): HTMLDivElement {
  const wrapper = document.createElement('div');
  wrapper.style.minWidth = 'var(--map-popup-min-width)';

  const name = document.createElement('strong');
  name.style.display = 'block';
  name.style.marginBlockEnd = 'var(--spacing-1)';
  name.textContent = vendor.displayName;

  const city = document.createElement('small');
  city.style.color = colors.muted;
  city.textContent = vendor.city ?? '';

  const breakElement = document.createElement('br');
  const link = document.createElement('a');
  link.href = `/business/${vendor.id}`;
  link.style.color = colors.link;
  link.style.fontSize = 'var(--font-size-xs)';
  link.textContent = linkLabel;

  wrapper.appendChild(name);
  wrapper.appendChild(city);
  wrapper.appendChild(breakElement);
  wrapper.appendChild(link);
  return wrapper;
}

/**
 * StoresMap - renders an OpenStreetMap with a marker per vendor.
 * Clicking a marker opens a popup with a link to the business page.
 *
 * Fully client-side: Leaflet is imported dynamically inside useEffect.
 */
export function StoresMap({ vendors, className = 'h-[var(--stores-map-height)]' }: StoresMapProps) {
  const tMap = useT('domain_map');
  const containerRef = useRef<HTMLDivElement>(null);
  const [loaded, setLoaded] = useState(false);
  const vendorKey = vendors.map((vendor) => vendor.id).join(',');
  const vendorsSnapshot = JSON.stringify({ vendorKey, vendors });
  const stableVendors = useMemo(
    () => (JSON.parse(vendorsSnapshot) as { vendors: VendorCardData[] }).vendors,
    [vendorsSnapshot],
  );
  const openBusinessPageLabel = tMap('open_business_page');

  useEffect(() => {
    if (!containerRef.current) return;
    const container = containerRef.current;
    let leafletMap: { remove: () => void } | null = null;
    let cancelled = false;

    void (async () => {
      await import('leaflet/dist/leaflet.css');
      if (cancelled) return;
      const L = (await import('leaflet')).default;
      if (cancelled) return;

      const map = L.map(container).setView([31.5, 34.9], 8);
      leafletMap = map;
      setLoaded(true);

      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
        maxZoom: 18,
      }).addTo(map);

      // Resolve design tokens for Leaflet popup HTML strings (Leaflet renders outside React tree)
      const rootStyle = getComputedStyle(document.documentElement);
      const colorTextMuted = rootStyle.getPropertyValue('--color-text-muted').trim();
      const colorTextLink = rootStyle.getPropertyValue('--color-text-link').trim();
      const markerColor = rootStyle.getPropertyValue('--color-brand-primary-500').trim();
      const markerStroke = rootStyle.getPropertyValue('--color-neutral-0').trim();

      // Add one marker per vendor that has coordinates
      const mappable = stableVendors.filter((v) => v.lat && v.lng);
      mappable.forEach((vendor) => {
        const lat = parseFloat(vendor.lat!);
        const lng = parseFloat(vendor.lng!);
        if (isNaN(lat) || isNaN(lng)) return;

        L.circleMarker([lat, lng], {
          radius: 8,
          color: markerStroke,
          fillColor: markerColor,
          fillOpacity: 1,
          weight: 2,
        })
          .addTo(map)
          .bindPopup(
            buildStorePopupContent(vendor, openBusinessPageLabel, {
              muted: colorTextMuted,
              link: colorTextLink,
            }),
          );
      });

      // Fit bounds to all markers if we have some
      if (mappable.length > 0) {
        const coords = mappable
          .map((v) => [parseFloat(v.lat!), parseFloat(v.lng!)] as [number, number])
          .filter(([lat, lng]) => !isNaN(lat) && !isNaN(lng));
        if (coords.length > 1) {
          map.fitBounds(coords, { padding: [40, 40] });
        }
      }
    })();

    return () => {
      cancelled = true;
      leafletMap?.remove();
    };
  }, [openBusinessPageLabel, stableVendors]);

  return (
    <div className={cn('relative w-full overflow-hidden rounded-xl', className)}>
      {!loaded && <Skeleton className="absolute inset-0" />}
      <div className={cn('h-full w-full', !loaded && 'invisible')}>
        <div
          ref={containerRef}
          className="h-full w-full"
          aria-label={tMap('stores_map_aria_label')}
          role="region"
        />
      </div>
    </div>
  );
}
