import { Layer, Source } from 'react-map-gl/maplibre';

import { POSTCODE_ZOOM_THRESHOLD } from '../../lib/consts';
import { type OverlayId, OVERLAY_MIN_ZOOM } from '../../lib/overlays';

function overlayTileUrl(path: string): string {
  return `${window.location.origin}/api/overlays/${path}/{z}/{x}/{y}`;
}

export function OverlayTileLayers({
  activeOverlays,
  activeCrimeTypes,
  zoom,
}: {
  activeOverlays: Set<OverlayId>;
  activeCrimeTypes: Set<string>;
  zoom: number;
}) {
  if (zoom < POSTCODE_ZOOM_THRESHOLD || activeOverlays.size === 0) return null;

  const showNoise = activeOverlays.has('noise');
  const showCrime = activeOverlays.has('crime-hotspots');
  const showTrees = activeOverlays.has('trees-outside-woodlands');
  const showPropertyBorders = activeOverlays.has('property-borders');

  // Restrict the heatmap to the selected crime types. This must always be a
  // concrete expression: passing `filter={undefined}` makes react-map-gl call
  // map.addLayer({filter: undefined}), which MapLibre rejects at validation
  // ("filter: array expected, undefined found"), so the layer is never created
  // and the heatmap stays blank until a later setFilter call. An `in` over the
  // selected types matches everything when all 14 are selected.
  const crimeFilter = ['in', ['get', 'crime_type'], ['literal', Array.from(activeCrimeTypes)]];

  return (
    <>
      {showNoise && (
        <Source
          id="overlay-noise-source"
          type="raster"
          tiles={[overlayTileUrl('noise')]}
          tileSize={256}
          minzoom={OVERLAY_MIN_ZOOM.noise}
          maxzoom={14}
        >
          <Layer
            id="overlay-noise"
            type="raster"
            minzoom={POSTCODE_ZOOM_THRESHOLD}
            paint={{
              'raster-opacity': 0.68,
              'raster-fade-duration': 120,
            }}
          />
        </Source>
      )}

      {showCrime && (
        <Source
          id="overlay-crime-source"
          type="vector"
          tiles={[overlayTileUrl('crime-hotspots')]}
          minzoom={OVERLAY_MIN_ZOOM['crime-hotspots']}
          maxzoom={15}
        >
          <Layer
            id="overlay-crime-heatmap"
            type="heatmap"
            source-layer="crime_hotspots"
            minzoom={POSTCODE_ZOOM_THRESHOLD}
            filter={crimeFilter as never}
            paint={
              {
                'heatmap-weight': [
                  'interpolate',
                  ['linear'],
                  ['coalesce', ['get', 'count'], ['get', 'weight'], 1],
                  0,
                  0,
                  10,
                  1,
                ],
                'heatmap-intensity': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2.2],
                'heatmap-radius': ['interpolate', ['linear'], ['zoom'], 15, 18, 18, 30],
                'heatmap-opacity': 0.72,
                'heatmap-color': [
                  'interpolate',
                  ['linear'],
                  ['heatmap-density'],
                  0,
                  'rgba(0, 0, 0, 0)',
                  0.2,
                  'rgb(253, 224, 71)',
                  0.45,
                  'rgb(249, 115, 22)',
                  0.75,
                  'rgb(220, 38, 38)',
                  1,
                  'rgb(127, 29, 29)',
                ],
              } as never
            }
          />
        </Source>
      )}

      {showTrees && (
        <Source
          id="overlay-trees-source"
          type="vector"
          tiles={[overlayTileUrl('trees-outside-woodlands')]}
          minzoom={OVERLAY_MIN_ZOOM['trees-outside-woodlands']}
          maxzoom={16}
        >
          <Layer
            id="overlay-tree-polygons"
            type="fill"
            source-layer="trees_outside_woodlands"
            minzoom={POSTCODE_ZOOM_THRESHOLD}
            paint={
              {
                'fill-color': '#1f9d55',
                'fill-opacity': [
                  'interpolate',
                  ['linear'],
                  ['coalesce', ['get', 'area_sqm'], 0],
                  0,
                  0.28,
                  250,
                  0.62,
                ],
                'fill-outline-color': 'rgba(15, 81, 50, 0.65)',
              } as never
            }
          />
        </Source>
      )}

      {showPropertyBorders && (
        <Source
          id="overlay-property-borders-source"
          type="vector"
          tiles={[overlayTileUrl('property-borders')]}
          minzoom={OVERLAY_MIN_ZOOM['property-borders']}
          maxzoom={16}
        >
          <Layer
            id="overlay-property-borders"
            type="line"
            source-layer="property_borders"
            minzoom={POSTCODE_ZOOM_THRESHOLD}
            paint={
              {
                'line-color': '#b45309',
                'line-opacity': ['interpolate', ['linear'], ['zoom'], 15, 0.35, 18, 0.85],
                'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.4, 18, 1.4],
              } as never
            }
          />
        </Source>
      )}
    </>
  );
}
