import { useEffect, useState } from 'react';
import { useRuntimeConfig } from '@/config/context';
import { cn } from '@/lib/utils';
import { getMap } from './map-view';
import { useMapPrefStore } from './map-pref-store';
import { BASEMAP_STYLES, ensureGoogleProtocol, type BasemapDescriptor } from './styles';

/**
 * Floating basemap-picker control, top-right of the map.
 *
 * Reads the persisted choice from `useMapPrefStore` and applies it to the
 * map via `map.setStyle(...)`. Style swap fires the `mapReady` gate which
 * coordinates the unmount/remount of every other `Map*` component on the
 * map (sprites, sources, layers all get re-applied).
 */
export function BasemapSwitcher() {
  const cfg = useRuntimeConfig();
  const current = useMapPrefStore((s) => s.basemapId);
  const setBasemap = useMapPrefStore((s) => s.setBasemap);
  const [switching, setSwitching] = useState<string | null>(null);

  const available = BASEMAP_STYLES.filter((d) => d.available(cfg));

  // Bootstrap: apply the persisted basemap once at mount. The singleton
  // boots with OSM as a bootstrap; this flips to the user's saved choice.
  // No `switching` UI state needed here — there's nothing to indicate to
  // the user during the very first style swap.
  useEffect(() => {
    const descriptor = available.find((d) => d.id === current);
    if (!descriptor) return;
    void (async () => {
      if (descriptor.id === 'google-satellite') {
        await ensureGoogleProtocol();
      }
      getMap().setStyle(descriptor.buildStyle(cfg));
    })();
    // Run-once on mount. The user-driven onClick path handles subsequent
    // changes; depending on `available` / `cfg` here would re-run the
    // bootstrap unnecessarily.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  async function onClick(descriptor: BasemapDescriptor): Promise<void> {
    if (current === descriptor.id) return;
    setBasemap(descriptor.id);
    setSwitching(descriptor.id);
    try {
      if (descriptor.id === 'google-satellite') {
        await ensureGoogleProtocol();
      }
      getMap().setStyle(descriptor.buildStyle(cfg));
    } finally {
      setSwitching(null);
    }
  }

  return (
    <div className="absolute top-3 right-3 bg-background border border-border rounded-md shadow-sm overflow-hidden z-10">
      {available.map((d) => {
        const isActive = current === d.id;
        const isPending = switching === d.id;
        return (
          <button
            key={d.id}
            type="button"
            onClick={() => void onClick(d)}
            disabled={isPending}
            className={cn(
              'block w-full text-left px-3 py-1.5 text-sm transition-colors',
              isActive ? 'bg-accent text-accent-foreground' : 'hover:bg-accent/50 text-foreground',
              isPending && 'opacity-50',
            )}
          >
            {d.label}
          </button>
        );
      })}
    </div>
  );
}
