import { useRef, useEffect } from 'react';

import { useTranslation } from 'react-i18next';

import MapView from '@arcgis/core/views/MapView';
import Basemap from '@arcgis/core/Basemap';
import esriRequest from '@arcgis/core/request';
import BaseTileLayer from '@arcgis/core/layers/BaseTileLayer';
import BasemapGallery from '@arcgis/core/widgets/BasemapGallery';
import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer';
import TileLayer from '@arcgis/core/layers/TileLayer';

const BEVURL = 'https://maps.bev.gv.at/tiles/{z}/{x}/{y}.png';

export default function Basemaps({ view }: { view: MapView }) {
  const basemapGalleryContainer = useRef<HTMLDivElement | null>(null);
  const rendered = useRef<boolean>(false);

  const { t } = useTranslation();

  const BEVTileLayer = (BaseTileLayer as any).createSubclass({
    // define instance properties
    properties: {
      urlTemplate: null,
    },

    // generate the tile url for a given level, row and column
    getTileUrl: function (level: number, row: number, col: number) {
      const z = level.toString().padStart(2, '0');
      let x = row.toString().padStart(9, '0');
      let y = col.toString().padStart(9, '0');

      // this is the BEV tiling scheme
      x = x.substring(0, 3) + '/' + x.substring(3, 3) + '/' + x.substring(6, 3);
      y = y.substring(0, 3) + '/' + y.substring(3, 3) + '/' + y.substring(6, 3);

      return this.urlTemplate.replace(/\{z\}/g, z).replace(/\{x\}/g, y).replace(/\{y\}/g, x);
    },

    // This method fetches tiles for the specified level and size.
    fetchTile: function (level: number, row: number, col: number, options: any) {
      // get the url for this tile
      const url = this.getTileUrl(level, row, col);

      // request for tiles based on the generated url
      // the signal option ensures that obsolete requests are aborted
      return esriRequest(url, {
        responseType: 'image',
      }).then(
        function (this: any, response: any) {
          // when esri request resolves successfully
          // get the image from the response
          const image = response.data;
          const width = this.tileInfo.size[0];
          const height = this.tileInfo.size[0];

          // create a canvas with 2D rendering context
          const canvas = document.createElement('canvas');
          const context = canvas.getContext('2d');
          canvas.width = width;
          canvas.height = height;

          // Draw the blended image onto the canvas.
          context?.drawImage(image, 0, 0, width, height);
          const imageData = context?.getImageData(0, 0, canvas.width, canvas.height);
          if (imageData) context?.putImageData(imageData, 0, 0);

          return canvas;
        }.bind(this)
      );
    },

    copyright: t('basemaps.copyright-bev'),
  });

  useEffect(() => {
    if (rendered.current) return;
    rendered.current = true;

    if (view) {
      const topoLayer = new BEVTileLayer({
        urlTemplate: BEVURL,
        title: 'BEV-Topografie',
      });

      const basemapBEV = new Basemap({
        baseLayers: [topoLayer],
        title: t('basemaps.basemap-bev-title'),
        id: 'basemap',
        thumbnailUrl:
          'https://gis.geosphere.at/portal/sharing/rest/content/items/1a94736328a1458abe435d23508f1822/data',
      });

      const basemapAT = new Basemap({
        portalItem: {
          id: 'df7d6cc9be754db8970614d2ee661f57',
          portal: {
            url: 'https://gis.geosphere.at/portal',
          },
        },
      });

      const basemapOSM = new Basemap({
        portalItem: {
          id: '5f6efd84434842fb9dcdcf6b9116dcd9',
          portal: { url: 'https://gis.geosphere.at/portal' },
        },
      });

      const lightgrayBase = new VectorTileLayer({
        url: 'https://gis.geosphere.at/portal/sharing/rest/content/items/291da5eab3a0412593b66d384379f89f/resources/styles/root.json',
        opacity: 0.5,
      });
      const lightGrayReference = new VectorTileLayer({
        url: 'https://gis.geosphere.at/portal/sharing/rest/content/items/1768e8369a214dfab4e2167d5c5f2454/resources/styles/root.json',
        opacity: 1,
      });
      const worldHillshade = new TileLayer({
        url: 'https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer',
      });
      const basemapEsri = new Basemap({
        baseLayers: [worldHillshade, lightgrayBase, lightGrayReference],
        title: t('basemaps.basemap-esri-title'),
        thumbnailUrl:
          'https://gis.geosphere.at/portal/sharing/rest/content/items/3eb1510943be4f29ae01c01ce229d8ba/data',
      });

      const basemapGalleryDiv = document.createElement('div');
      basemapGalleryContainer.current?.append(basemapGalleryDiv);

      new BasemapGallery({
        container: basemapGalleryDiv,
        view: view,
        source: [basemapAT, basemapBEV, basemapOSM, basemapEsri],
      });
    }

    return () => {};
  });

  return <div ref={basemapGalleryContainer}></div>;
}
