import { useEffect, useRef, useState } from 'react';
import type maplibregl from 'maplibre-gl';
import type { FeedItem } from './types';
import { findCentroid } from './county-centroids';
import { formatRON } from './utils';

interface Pulse {
  id: string;
  lng: number;
  lat: number;
  value: number;
  authority: string;
  bornAt: number;
}

const PULSE_LIFETIME_MS = 6000;
const MAX_VISIBLE = 6;

interface Props {
  map: maplibregl.Map | null;
  newItems: FeedItem[];
}

export function PulseLayer({ map, newItems }: Props) {
  const [pulses, setPulses] = useState<Pulse[]>([]);
  const [, setTick] = useState(0);
  const seenIds = useRef<Set<string>>(new Set());

  // Add new items as pulses (dedup by item id)
  useEffect(() => {
    if (!map || newItems.length === 0) return;

    const fresh: Pulse[] = [];
    for (const item of newItems.slice(0, MAX_VISIBLE)) {
      const key = `${item.type}-${item.id}`;
      if (seenIds.current.has(key)) continue;
      seenIds.current.add(key);

      const centroid = findCentroid(item.authority_county);
      if (!centroid) continue;

      // jitter so multiple pulses in same county don't perfectly overlap
      const jitterLng = (Math.random() - 0.5) * 0.25;
      const jitterLat = (Math.random() - 0.5) * 0.15;

      fresh.push({
        id: key,
        lng: centroid[0] + jitterLng,
        lat: centroid[1] + jitterLat,
        value: Number(item.value || 0),
        authority: item.authority_name,
        bornAt: Date.now(),
      });
    }

    if (fresh.length > 0) {
      setPulses((prev) => [...prev, ...fresh].slice(-MAX_VISIBLE * 3));
    }
  }, [newItems, map]);

  // Tick to re-render projected positions on map move/zoom
  useEffect(() => {
    if (!map) return;
    const tick = () => setTick((t) => t + 1);
    map.on('move', tick);
    map.on('zoom', tick);
    return () => {
      map.off('move', tick);
      map.off('zoom', tick);
    };
  }, [map]);

  // Garbage collect expired pulses
  useEffect(() => {
    if (pulses.length === 0) return;
    const id = setInterval(() => {
      const now = Date.now();
      setPulses((prev) => prev.filter((p) => now - p.bornAt < PULSE_LIFETIME_MS));
    }, 1000);
    return () => clearInterval(id);
  }, [pulses.length]);

  if (!map) return null;

  return (
    <div className="absolute inset-0 pointer-events-none overflow-hidden z-[5]">
      {pulses.map((p) => {
        const proj = map.project([p.lng, p.lat]);
        const ageMs = Date.now() - p.bornAt;
        if (ageMs > PULSE_LIFETIME_MS) return null;

        // Bigger pulses for higher-value contracts
        const sizeMult = p.value >= 1_000_000 ? 1.3 : p.value >= 100_000 ? 1.0 : 0.75;

        return (
          <div
            key={p.id}
            className="harta-pulse-wrap"
            style={{
              left: proj.x,
              top: proj.y,
              ['--pulse-size' as any]: `${sizeMult}`,
            }}
          >
            <div className="harta-pulse-ring" />
            <div className="harta-pulse-ring harta-pulse-ring-2" />
            <div className="harta-pulse-dot" />
            {sizeMult >= 1.0 && ageMs < 2500 && (
              <div className="harta-pulse-label tabular-nums">
                {formatRON(p.value)}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}
