import { Component, createEffect, createSignal, onMount } from 'solid-js';
import { createStore } from 'solid-js/store';
import { useParams, useNavigate } from '@solidjs/router';
import OlMap from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature';
import Attribution from 'ol/control/Attribution';
import Rotate from 'ol/control/Rotate';
import ScaleLine from 'ol/control/ScaleLine';
import Control from 'ol/control/Control';
import { useGeographic as olUseGeographic } from 'ol/proj';
import DragRotate from 'ol/interaction/DragRotate';

import 'ol/ol.css';
import './Map.css';
import { Collection } from 'ol';
import { Point } from 'ol/geom';
import { Style, Icon } from 'ol/style';
import GetLocation, { getCurrentLocation } from '../get-location';
import ShowLocationIcon from '../get-location/ShowLocationIcon.svg';
import { Back, Forward } from '../back-forward';
import GpxImport from '../gpx-import';
import AllGpxes from '../all-gpxes';
import MapTileProvider, { mapTileProviders } from '../map-tile-provider';
import Interaction from 'ol/interaction/Interaction';
import DoubleClickZoom from 'ol/interaction/DoubleClickZoom';
import DragPan from 'ol/interaction/DragPan';
import PinchRotate from 'ol/interaction/PinchRotate';
import PinchZoom from 'ol/interaction/PinchZoom';
import KeyboardPan from 'ol/interaction/KeyboardPan';
import KeyboardZoom from 'ol/interaction/KeyboardZoom';
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom';
import DragZoom from 'ol/interaction/DragZoom';
import Infos, { clickHandler } from '../infos';

const [getState, setState] = createSignal({
  lon: 0,
  lat: 0,
  rotation: 0,
  zoom: 0,
  provider: 'osm',
});

export { getState };

const [getMap, setMap] = createSignal<OlMap | null>(null);

export { getMap };

const Map: Component = () => {
  const params = useParams();
  const navigate = useNavigate();

  let target: HTMLDivElement;

  createEffect(() => {
    console.log({
      caller: 'Map / setState',
      params: {
        ...params,
      },
    });
    setState({
      provider: params.provider,
      lon: +params.lon,
      lat: +params.lat,
      rotation: +params.rotation,
      zoom: +params.zoom,
    });
    const map = getMap();

    const layers = map?.getLayers();
    const tileLayer = layers?.item(0) as TileLayer<any> | undefined;
    if (tileLayer?.get('provider') !== params.provider) {
      tileLayer?.set('provider', params.provider, true);
      tileLayer?.setSource(mapTileProviders[params.provider].source);
    }

    const view = map?.getView();
    view?.animate({
      center: [getState().lon, getState().lat],
      rotation: getState().rotation,
      zoom: getState().zoom,
      duration: 1000,
    });
  });

  createEffect(() => {
    const location = getCurrentLocation();
    if (location) {
      console.log({
        caller: 'Map / updateLocation',
        location,
      });
      const source = getMap()
        ?.getAllLayers()
        .at(1)
        ?.getSource() as VectorSource;
      source!.clear(true);
      const point = new Point([location.lon, location.lat]);
      const style = new Style({
        image: new Icon({
          //      size: [20, 20],
          imgSize: [24, 24],
          declutterMode: 'obstacle',
          // @ts-ignore
          src: ShowLocationIcon,
        }),
      });
      const feature = new Feature({
        geometry: point,
        //      labelPoint: point,
        //      name: 'current location',
        style: style,
      });
      feature.set('type', 'current-location');
      feature.setStyle(style);
      source.addFeature(feature);
      //    source.changed();
      console.log({
        caller: 'Map / updateLocation',
        location,
        source,
        style,
        feature,
      });
    }
  });

  onMount(() => {
    olUseGeographic();

    const changeListener = (event: any) => {
      const map = getMap();
      const view = map?.getView();
      const center = view?.getCenter();
      if (center) {
        navigate(
          `/map/${getState().provider}/${center[0]}/${
            center[1]
          }/${view?.getZoom()}/${view?.getRotation()}`
        );
      }
      console.log({
        caller: 'Map / changeListener',
        event,
        params: {
          ...params,
        },
        map,
      });
    };

    const tileLayer = new TileLayer({
      source: mapTileProviders[params.provider].source,
    });
    tileLayer.set('provider', params.provider, true);

    const vectorLayer = new VectorLayer({
      source: new VectorSource(),
      zIndex: Infinity,
    });

    const olMap = new OlMap({
      view: new View({
        center: [+getState().lon, +getState().lat],
        zoom: +getState().zoom,
        rotation: +getState().rotation,
      }),
      layers: [tileLayer, vectorLayer],
      target: target,
      controls: new Collection<Control>([
        new Attribution({ collapsible: true }),
        new Rotate(),
        new ScaleLine({ bar: true }),
      ]),
      moveTolerance: 10,
      interactions: new Collection<Interaction>([
        new DragRotate(),
        new DoubleClickZoom(),
        new DragPan(),
        new PinchRotate(),
        new PinchZoom(),
        new KeyboardPan(),
        new KeyboardZoom(),
        new MouseWheelZoom(),
        new DragZoom(),
      ]),
    });
    olMap.on(['moveend'], changeListener);
    olMap.on(['singleclick'], clickHandler);

    setMap(olMap);
  });

  return (
    // @ts-ignore
    <div class='ol-map' ref={target}>
      <GetLocation />
      <Forward />
      <Back />
      <GpxImport />
      <MapTileProvider />
      <AllGpxes map={getMap} />
      <Infos />
    </div>
  );
};

export default Map;
