import './style.css';
import {Map, View} from 'ol';
import {fromLonLat, get, transform} from 'ol/proj.js';
import {defaults as defaultControls} from 'ol/control.js';
import Overlay from 'ol/Overlay.js';

import ContextMenu from 'ol-contextmenu';

import ToggleMenuControl from './ui/controls.js';

import layerCategories from './layers/index.js';

// from https://openlayers.org/en/latest/examples/popup.html
const container = document.getElementById('popup');
const content = document.getElementById('popup-content');
const closer = document.getElementById('popup-closer');
const popupOverlay = new Overlay({
  element: container,
  autoPan: {
    animation: {
      duration: 250,
    },
  },
});

const contextMenu = new ContextMenu({
  width: 170,
  defaultItems: false,
  items: [
      {
          text: 'Open on OSM',
          callback: obj => {
            const coords = transform(obj.coordinate, 'EPSG:3857', 'EPSG:4326')
            window.open(
              `https://www.openstreetmap.org/#map=${map.getView().getZoom()}/${coords[1]}/${coords[0]}`,
              "_blank",
            );
          },
      },
      {
          text: 'Copy lat/long',
          callback: async function(obj){
            const coords = transform(obj.coordinate, 'EPSG:3857', 'EPSG:4326')
            try {
              await navigator.clipboard.writeText(`${coords[1]}, ${coords[0]}`);
            } catch (error) {
              console.error(error.message);
            }
          },
      },
  ],
});

const map = new Map({
  controls: defaultControls().extend([new ToggleMenuControl(), contextMenu]),
  target: 'map',
  layers: [],
  overlays: [popupOverlay],
  view: new View({
    center: fromLonLat([-93.24151, 44.80376]),
    zoom: 10,
  })
});

// Basic reactivity binding: like vue.js, just worse :)
//
// This implements some basic reactivity so that I can add and remove layers.
// Nothing too fancy, at this point. Eventually, I'll likely pull in proper Vue,
// as I aim for more complex interactions, like layer ordering, color selection,
// custom layer imports, and more.
for (let category of layerCategories) {
  const catDiv = document.createElement("div");
  catDiv.innerHTML = `
    <details ${category.layers.filter(l => l.enabled).length > 0 ? "open" : ""}>
    <summary>${category.name}</summary>
    ${category.details ? "<p>" + category.details + "</p>" : ""}
    <ul></ul>
    </details>
  `;
  for (let layer of category.layers) {
    const li = document.createElement("li");
    li.innerHTML = `
      <label><input type="checkbox" ${layer.enabled ? "checked" : ""}> ${layer.name}</label>
    `;
    li.querySelector("input").addEventListener("change", function(e){
      if (e.target.checked) {
        map.getLayers().push(layer.layer);
      } else {
        map.getLayers().remove(layer.layer);
      }
    });
    catDiv.querySelector("ul").appendChild(li);
  }
  document.querySelector("aside").appendChild(catDiv);
}

for (let category of layerCategories) {
  for (let layer of category.layers) {
    if (layer.enabled) {
      map.addLayer(layer.layer);
    }
  }
}

function objectToTable(o) {
  // TODO: hack hack hack
  let table = `<table style="margin: 0.5em; border-collapse: collapse;">`;
  for (let [key, value] of Object.entries(o)) {
    if (typeof value === "object") {
      value = objectToTable(value);
    }
    if (typeof value === "string" && value.startsWith('https://')) {
      value = `<a href="${value}">${value}</a>`
    }
    table += `<tr><td style="border: 1px solid;">${key}</td><td style="border: 1px solid;">${value}</td></tr>`;
  }
  table += `</table>`;
  return table;
}

// from https://openlayers.org/en/latest/examples/icon.html
map.on('click', function (evt) {
  let layer;
  const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature, l) {
    layer = l;
    return feature;
  });
  if (!feature) {
    return;
  }
  if (layer.hasOwnProperty('customPopup')) {
    content.innerHTML = layer.customPopup(feature);
    if (layer.hasOwnProperty('customPopupCallback')) {
      layer.customPopupCallback(feature);
    }
  } else {
    // exclude geometry -- https://stackoverflow.com/a/208106
    const {geometry: _, ...featureData} = feature.getProperties();

    content.innerHTML = objectToTable(featureData);
  }

  popupOverlay.setPosition(evt.coordinate);

  closer.onclick = function (){
    popupOverlay.setPosition(undefined);
    if (layer.hasOwnProperty('destroyPopupCallback')) {
      layer.destroyPopupCallback(feature);
    }
    closer.blur();
    return false;
  };
});

new ResizeObserver(() => map.updateSize()).observe(document.getElementById("map"));

window.map = map;

document.getElementById('source').innerHTML = `<a href="https://git.chandlerswift.com/chandlerswift/maps.chandlerswift.com/commit/${import.meta.env.VITE_GIT_COMMIT_HASH}">Source code</a>
<!--
${import.meta.env.VITE_FILE_DATES}
-->`;