import { Component, createEffect, createSignal, onMount } from 'solid-js';
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 { fromLonLat, toLonLat } 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, Circle, Fill } 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 Cluster from 'ol/source/Cluster.js';
import * as olExtent from 'ol/extent';
import DragZoom from 'ol/interaction/DragZoom';
import Infos, { clickHandler } from '../infos';
import GpxDialog from '../gpx-dialog';
import GpxRecord from '../gpx-record';
import dispatch from '../../workers/dispatcher-main';
import { debounce } from 'lodash';

import { AndroidFullScreen } from '@awesome-cordova-plugins/android-full-screen';
import Account from '../account';
import OsmFetch from '../osm-fetch';
import VectorTileLayer from 'ol/layer/VectorTile';
import VectorTileSource from 'ol/source/VectorTile.js';
import MVT from 'ol/format/MVT.js';
import style from '../gpx/styles';
import ClusterableVectorTileSourceProxy from '../../lib/ClusterableVectorTileSourceProxy';
import { Overlays } from '../overlays/Overlays';

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

const getZoomInteger = () => Math.floor(getState().zoom);

export { getState, getZoomInteger };

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

export { getMap };

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

  // See https://stackoverflow.com/questions/71288670/how-to-make-fullscreen-ionic-capacitor-app
  AndroidFullScreen.isImmersiveModeSupported()
    .then(() => AndroidFullScreen.immersiveMode())
    .catch(console.warn);

  if (window.plugins) {
    window.plugins.intentShim.registerBroadcastReceiver(
      {
        filterActions: ['android.intent.action.VIEW'],
      },
      function (intent: any) {
        console.log({
          caller: 'Intent broadcast receiver',
          intent,
        });
      }
    );
    window.plugins.intentShim.onIntent(function (intent: any) {
      console.log({ caller: 'Intent receiver', intent });
      const url = new URL(intent.data);
      const q = url.search;
      const [, lat, lon] = q.match(/q=([0-9.]+),([0-9.]+)/);
      const zoom = Math.min(18, getState().zoom);
      navigate(
        `/map/${getState().provider}/${lon}/${lat}/${zoom}/${
          getState().rotation
        }`
      );
    });
  } else {
    console.log({
      caller: 'Intent',
      message: "window.plugins doesn't exist",
      window,
    });
  }

  if (
    params.lat === '0' &&
    params.lon === '0' &&
    params.provider === 'osm' &&
    params.rotation === '0' &&
    params.zoom === '2'
  ) {
    dispatch({ action: 'getState' }, (error, state) => {
      if (state !== null) {
        console;
        navigate(
          `/map/${state.provider}/${state.lon}/${state.lat}/${state.zoom}/${state.rotation}`
        );
      }
    });
  }

  let target: HTMLDivElement;

  const debouncedDbSetState = debounce((state: any) => {
    console.log({ caller: 'Map / debouncedDbSetState', state });
    dispatch({ action: 'setState', params: state });
  }, 60000);

  createEffect(async () => {
    console.log({
      caller: 'Map / setState',
      params: {
        ...params,
      },
    });
    setState({
      provider: params.provider,
      lon: +params.lon,
      lat: +params.lat,
      rotation: +params.rotation,
      zoom: +params.zoom,
    });
    debouncedDbSetState(getState());
    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: fromLonLat([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(fromLonLat([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(async () => {
    //  olUseGeographic();

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

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

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

    //  console.log({
    //   caller: 'Map / projections',
    //   vector: vectorLayer.getSource()?.getProjection(),
    //   vectorTile: clusterableVectorTileSource.getProjection(),
    // });

    const olMap = new OlMap({
      view: new View({
        center: fromLonLat([+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 (
    //<OsmFetch map={getMap} />
    // @ts-ignore
    <div class='ol-map' ref={target}>
      <Overlays map={getMap} />
      <GetLocation />
      <Forward />
      <Back />
      <GpxRecord />
      <GpxImport />
      <MapTileProvider />
      <GpxDialog />
      <Account />
      <AllGpxes map={getMap} />
      <Infos />
    </div>
  );
};

export default Map;
