import { default as L } from 'leaflet';
import 'leaflet-svg-shape-markers';
import { createRef, Fragment, useEffect, type FC } from 'react';
import { GeoJSON, ImageOverlay, MapContainer, TileLayer } from 'react-leaflet';

interface MapProps {
  airport: Airport | undefined;
  chart: Chart | undefined;
  procedures: Procedure[];
}

export const Map: FC<MapProps> = ({ airport, chart, procedures }) => {
  const mapRef = createRef<L.Map>();
  const imageRef = createRef<L.ImageOverlay>();

  useEffect(() => {
    if (airport) mapRef.current?.flyTo([airport?.Latitude, airport?.Longitude], 10, { animate: false });
  }, [airport]);

  return (
    <MapContainer
      center={[0, 0]}
      zoom={5}
      zoomSnap={0}
      className="h-full w-full"
      ref={(_mapRef) => {
        _mapRef?.attributionControl.setPosition('topright');
        _mapRef?.zoomControl.setPosition('topright');
        mapRef.current = _mapRef;
      }}
    >
      <TileLayer
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />

      {chart && chart.bounds && (
        <ImageOverlay
          url={chart.data}
          bounds={chart.bounds}
          opacity={0.75}
          ref={(_imageRef) => {
            if (_imageRef) {
              mapRef.current?.fitBounds(_imageRef.getBounds(), {
                padding: [-50, -50],
              });
            }
            imageRef.current = _imageRef;
          }}
        />
      )}

      {procedures.map((procedure) => (
        <Fragment key={procedure.name}>
          <GeoJSON
            key={`${procedure.name}-lines`}
            data={procedure.data}
            style={({ properties }) => ({
              color: properties.isMAP ? '#00ffff' : '#ff00ff',
              stroke: true,
              weight: properties.isMAP ? 2.5 : 5,
              opacity: 1,
              dashArray: properties.isManual ? '20, 20' : undefined,
            })}
            filter={(feature) => feature.geometry.type !== 'Point'}
          />
          <GeoJSON
            key={`${procedure.name}-points`}
            data={procedure.data}
            style={{
              color: 'black',
              fill: true,
              fillColor: 'transparent',
              stroke: true,
              weight: 3,
            }}
            pointToLayer={({ properties }, latlng) => {
              if (properties.isIntersection) return L.circleMarker(latlng, { radius: 6 });
              else if (properties.IsMAP)
                return L.shapeMarker(latlng, {
                  shape: 'square',
                  radius: 6,
                });
              else if (properties.IsFAF)
                return L.shapeMarker(latlng, {
                  shape: 'diamond',
                  radius: 6,
                });
              else if (properties.isFlyOver)
                return L.shapeMarker(latlng, {
                  shape: 'triangle',
                  radius: 6,
                });

              return L.shapeMarker(latlng, {
                shape: 'star-4',
                radius: 10,
                rotation: 45,
              });
            }}
            onEachFeature={({ geometry, properties }, layer) => {
              if (geometry.type === 'Point') {
                layer.bindPopup(
                  `${properties.name}<br>
                ${properties.altitude} ft<br>
                ${properties.speed} kts<br>
                CNSTR: 
                ${properties.altitudeConstraint ?? ''}
                ${properties.speedConstraint ?? ''}<br>`
                );
              }
            }}
            filter={(feature) => feature.geometry.type === 'Point'}
          />
        </Fragment>
      ))}
    </MapContainer>
  );
};
