// Map view — the original globe + filters + list, extracted into a component.
const { useState: useSM, useEffect: useEM, useMemo: useMM, useCallback: useCbM } = React;

function MapView({ selectedId, setSelectedId }) {
  const store = useStore();
  const user = store.getCurrentUser();

  const [userCities, setUserCities] = useSM(() => {
    try { return JSON.parse(localStorage.getItem('expat-user-cities') || '[]'); } catch { return []; }
  });
  const locations = useMM(() => [...window.EXPAT_LOCATIONS, ...userCities], [userCities]);
  const [countryPolygons, setCountryPolygons] = useSM(null);
  const [filters, setFilters] = useSM(window.DEFAULT_FILTERS);
  const [hoveredId, setHoveredId] = useSM(null);
  const [favorites, setFavorites] = useSM(() => {
    try { return new Set(JSON.parse(localStorage.getItem('expat-favs') || '[]')); } catch { return new Set(); }
  });
  const [sortBy, setSortBy] = useSM('relevance');
  const [tab, setTab] = useSM('filters');

  useEM(() => { localStorage.setItem('expat-user-cities', JSON.stringify(userCities)); }, [userCities]);
  useEM(() => { localStorage.setItem('expat-favs', JSON.stringify([...favorites])); }, [favorites]);

  // Pull favorites from cloud when signed in (on mount + on auth change)
  useEM(() => {
    if (!window.fsnCloud?.enabled) return;
    const unsub = window.fsnCloud.onSession(async (session) => {
      if (!session) return;
      const cloudFavs = await window.fsnCloud.getFavorites();
      if (cloudFavs && cloudFavs.length > 0) {
        setFavorites(new Set(cloudFavs));
      }
    });
    return unsub;
  }, []);

  useEM(() => {
    (async () => {
      try {
        const res = await fetch('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json');
        const topo = await res.json();
        const geo = window.topojson.feature(topo, topo.objects.countries);
        const rings = [];
        for (const feat of geo.features) {
          const g = feat.geometry;
          if (!g) continue;
          if (g.type === 'Polygon') for (const ring of g.coordinates) rings.push(ring);
          else if (g.type === 'MultiPolygon') for (const poly of g.coordinates) for (const ring of poly) rings.push(ring);
        }
        setCountryPolygons(rings);
      } catch (e) { console.warn('Could not load country outlines', e); }
    })();
  }, []);

  const toggleFav = useCbM((id) => {
    setFavorites(f => {
      const n = new Set(f);
      if (n.has(id)) {
        n.delete(id);
        if (window.fsnCloud?.enabled && window.fsnCloud.isSignedIn()) {
          window.fsnCloud.removeFavorite(id).catch(() => {});
        }
      } else {
        n.add(id);
        if (window.fsnCloud?.enabled && window.fsnCloud.isSignedIn()) {
          window.fsnCloud.addFavorite(id).catch(() => {});
        }
      }
      return n;
    });
  }, []);

  const matching = useMM(() => locations.filter(l => {
    if (filters.tiers.length > 0) {
      const okTier = filters.tiers.some(t => {
        const c = t === 'survival' ? l.costSurvival : t === 'comfort' ? l.costComfort : l.costLuxury;
        return c <= filters.maxCost;
      });
      if (!okTier) return false;
    } else if (l.costComfort > filters.maxCost) return false;
    if (filters.vibes.length > 0 && !filters.vibes.some(v => l.vibes.includes(v))) return false;
    if (filters.biomes.length > 0 && !filters.biomes.includes(l.biome)) return false;
    if (l.safety < filters.minSafety) return false;
    if (l.visaFlex < filters.minVisa) return false;
    if (l.internet < filters.minInternet) return false;
    if (l.healthcare < filters.minHealth) return false;
    return true;
  }), [locations, filters]);

  const matchingIds = useMM(() => new Set(matching.map(l => l.id)), [matching]);
  const sorted = useMM(() => {
    const arr = [...matching];
    if (sortBy === 'cost-asc') arr.sort((a,b) => a.costComfort - b.costComfort);
    else if (sortBy === 'cost-desc') arr.sort((a,b) => b.costComfort - a.costComfort);
    else if (sortBy === 'safety') arr.sort((a,b) => b.safety - a.safety);
    else if (sortBy === 'visa') arr.sort((a,b) => b.visaFlex - a.visaFlex);
    else arr.sort((a,b) => b.weight - a.weight);
    return arr;
  }, [matching, sortBy]);

  const selected = selectedId ? locations.find(l => l.id === selectedId) : null;

  const applyConciergeFilters = (f) => { setFilters({ ...window.DEFAULT_FILTERS, ...f }); setTab('list'); };
  const isFiltered = useMM(() => JSON.stringify(filters) !== JSON.stringify(window.DEFAULT_FILTERS), [filters]);

  // Add destination to active playbook (or create one)
  const addToPlaybook = (loc) => {
    if (!user) { window.dispatchEvent(new CustomEvent('expat:require-signin')); return; }
    const pbs = store.getPlaybooks();
    let pb = pbs[0];
    if (!pb) pb = store.createPlaybook(`${loc.name} trip`);
    store.addDestination(pb.id, {
      cityId: loc.id, label: `${loc.name}, ${loc.country}`, lat: loc.lat, lng: loc.lng,
      arrival: '', departure: '', userAdded: !!loc.userAdded,
    });
    window.dispatchEvent(new CustomEvent('expat:added-to-playbook', { detail: { pbId: pb.id, name: loc.name } }));
  };

  return (
    <div className="map-view">
      <div className="globe-side">
        <div className="brand">
          <div>
            <div className="brand-mark"><b>◉</b> EXPAT·HUB — GLOBAL PICKER</div>
            <h1 className="brand-title">Where next?</h1>
            <div className="brand-sub">{locations.length} hubs · {matching.length} match current filters</div>
          </div>
          <div className="brand-legend">
            <span><span className="legend-dot" style={{ width: 4, height: 4 }}/>minor</span>
            <span><span className="legend-dot" style={{ width: 7, height: 7 }}/>mid</span>
            <span><span className="legend-dot" style={{ width: 10, height: 10 }}/>major</span>
          </div>
        </div>
        <div className="globe-container">
          <Globe
            locations={locations}
            size={Math.min(640, window.innerHeight * 0.66)}
            selectedId={selectedId}
            hoveredId={hoveredId}
            favoritedIds={favorites}
            filterResultIds={matchingIds}
            countryPolygons={countryPolygons}
            onSelect={setSelectedId}
            onHover={setHoveredId}
          />
        </div>
        <div className="globe-hint">↺ DRAG · ⊖ SCROLL ZOOM · CLICK A DOT</div>
        {selected && (
          <div className="coord">
            {selected.lat.toFixed(2)}° {selected.lat >= 0 ? 'N' : 'S'} · {selected.lng.toFixed(2)}° {selected.lng >= 0 ? 'E' : 'W'}<br/>
            <span>{selected.name.toUpperCase()}</span>
          </div>
        )}
      </div>

      <div className="list-side">
        <div className="list-head">
          <div className="list-tabs">
            <button className={`list-tab ${tab === 'filters' ? 'on' : ''}`} onClick={() => setTab('filters')}>Filters</button>
            <button className={`list-tab ${tab === 'list' ? 'on' : ''}`} onClick={() => setTab('list')}>
              Results <span style={{ color: 'var(--accent)' }}>({matching.length})</span>
            </button>
          </div>
          {tab === 'list' && (
            <div className="sort-row">
              <span>SORTED BY</span>
              <select value={sortBy} onChange={e => setSortBy(e.target.value)}>
                <option value="relevance">Significance</option>
                <option value="cost-asc">Cost (low → high)</option>
                <option value="cost-desc">Cost (high → low)</option>
                <option value="safety">Safety</option>
                <option value="visa">Visa flexibility</option>
              </select>
            </div>
          )}
        </div>

        {tab === 'filters' && (
          <div style={{ flex: 1, overflowY: 'auto' }}>
            {isFiltered && (
              <div className="reset-filters-bar">
                <button className="reset-filters-btn" onClick={() => setFilters(window.DEFAULT_FILTERS)}>↺ RESET ALL FILTERS</button>
              </div>
            )}
            <FilterPanel filters={filters} setFilters={setFilters} counts={{ total: locations.length, matching: matching.length }}/>
            <div className="filter-panel" style={{ borderBottom: 0 }}>
              <div className="filter-label">Preview · top matches</div>
              <div className="result-list" style={{ paddingBottom: 40 }}>
                {sorted.slice(0, 5).map(loc => (
                  <ResultRow key={loc.id} loc={loc} selected={selectedId === loc.id} fav={favorites.has(loc.id)}
                    onClick={() => setSelectedId(loc.id)} onFav={(e) => { e.stopPropagation(); toggleFav(loc.id); }}/>
                ))}
              </div>
            </div>
          </div>
        )}

        {tab === 'list' && (
          <div className="result-list">
            {sorted.length === 0 && <div style={{ padding: 40, textAlign: 'center', color: 'var(--fg-dim)', fontFamily: 'IBM Plex Mono' }}>No hubs match. Loosen a filter.</div>}
            {sorted.map(loc => (
              <ResultRow key={loc.id} loc={loc} selected={selectedId === loc.id} fav={favorites.has(loc.id)}
                onClick={() => setSelectedId(loc.id)} onFav={(e) => { e.stopPropagation(); toggleFav(loc.id); }}/>
            ))}
          </div>
        )}
      </div>

      {selected && (
        <LocationCard
          loc={selected}
          onClose={() => setSelectedId(null)}
          isFav={favorites.has(selected.id)}
          onToggleFav={() => toggleFav(selected.id)}
          onAddToPlaybook={() => addToPlaybook(selected)}
          onDelete={selected.userAdded ? () => {
            setUserCities(arr => arr.filter(c => c.id !== selected.id));
            setFavorites(f => { const n = new Set(f); n.delete(selected.id); return n; });
            setSelectedId(null);
          } : null}
        />
      )}

      <Concierge locations={locations} onApplyFilters={applyConciergeFilters}/>
      <SettingsPanel />
      <AddCityButton onAdd={(city) => {
        setUserCities(arr => [...arr, city]);
        setFavorites(f => { const n = new Set(f); n.add(city.id); return n; });
        setSelectedId(city.id);
      }}/>
      <CompareTray
        favorites={favorites} locations={locations}
        onOpen={setSelectedId}
      onClear={() => {
          const ids = [...favorites];
          setFavorites(new Set());
          if (window.fsnCloud?.enabled && window.fsnCloud.isSignedIn()) {
            ids.forEach(id => window.fsnCloud.removeFavorite(id).catch(() => {}));
          }
        }}
        onRemove={(id) => toggleFav(id)}
      />
    </div>
  );
}

function ResultRow({ loc, selected, fav, onClick, onFav }) {
  return (
    <div className={`result-item ${selected ? 'selected' : ''} ${loc.userAdded ? 'user-added' : ''}`} onClick={onClick}>
      <div>
        <span className="ri-name">{loc.name}</span>
        <span className="ri-country">{loc.country}</span>
        {loc.userAdded && <span className="ri-userbadge">USER·ADDED</span>}
      </div>
      <div className="ri-cost">${loc.costComfort.toLocaleString()} <span>/mo comfort</span></div>
      <div className="ri-meta">
        <span><b>safety</b> {loc.safety}</span>
        <span><b>visa</b> {loc.visaFlex}</span>
        <span><b>{loc.biome.replace(/-/g,' ')}</b></span>
      </div>
      <button className={`ri-fav ${fav ? 'on' : ''}`} onClick={onFav} title="Favorite">
        <svg width="14" height="14" viewBox="0 0 16 16">
          <path d="M8 1l2.2 4.5L15 6.2l-3.5 3.4.8 4.9L8 12.2 3.7 14.5l.8-4.9L1 6.2l4.8-.7L8 1z"
            fill={fav ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="1.2" strokeLinejoin="round"/>
        </svg>
      </button>
    </div>
  );
}

window.MapView = MapView;
