<template>
  <Dropzone
    v-slot="{isDragOver}"
    class="map-control"
    :class="{
      'map-control--over': isDragOver
    }"
    @dropFile="onDrop"
    @mousewheel="onScroll"
    @mousedown="onMouseDown"
  >
    <button @click="reset()">reset</button>
    <select v-model="mode">
      <option value="drag">drag</option>
      <option value="draw">draw</option>
      <option value="measure">measure</option>
    </select>
    <select
      v-if="canvasDisplay?.mapLayer"
      v-model="canvasDisplay.mapLayer.grid"
    >
      <option value="none">no grid</option>
      <option value="light">light grid</option>
      <option value="dark">dark grid</option>
    </select>
    <select
      v-if="canvasDisplay?.mapLayer"
      v-model="canvasDisplay.mapLayer.rotation"
    >
      <option :value="0">0°</option>
      <option :value="1">90°</option>
      <option :value="2">180°</option>
      <option :value="3">270°</option>
    </select>
    <input
    v-if="canvasDisplay?.mapLayer"
      type="number"
      v-model="canvasDisplay.mapLayer.mapWidthInInches"
    />
    <div ref="rendererWrapper" v-show="canvasDisplay">
      <canvas :width="selectedScreen?.imageSink?.resolution.width" :height="selectedScreen?.imageSink?.resolution.height" ref="canvas" style="max-width: 100%;" />
    </div>
  </Dropzone>

</template>
<script setup lang="ts">
import {computed, inject, onBeforeUnmount, onMounted, reactive, ref} from 'vue';
import Dropzone from '../Dropzone/Dropzone.vue';
import MapRenderer from './MapRenderer.vue';
import {MountedFsSymbol, RemoteDeviceManagerSymbol} from '../../model/injectionSymbols';
import {closerToZero, MapDrawable, MapImage} from './helpers';
import {VirtualFile} from '../../model/FileSystem/types';
import {CanvasDisplay, MapLayerDrawable} from './object';
import {Devices} from '../../model/Remote/RemoteDeviceManager';

const fs = inject(MountedFsSymbol)!;
const remoteManager = inject(RemoteDeviceManagerSymbol)!;

const screens = computed(() => {
  return remoteManager.devices
    .filter(device => device.hasImageSink)
})

const canvas = ref<HTMLCanvasElement>();
const selectedScreen = ref<Devices>();
const pointerVisible = ref(false);
let canvasDisplay: undefined | CanvasDisplay;

function selectScreen (screen: any) {
  if (screen.imageSink?.display) {
    selectedScreen.value = screen;
    console.log('selectScreen!!!', screen.imageSink?.display);
    canvasDisplay?.disconnectTarget(canvas.value!);
    canvasDisplay = screen.imageSink?.display;
    canvasDisplay?.connectTarget(canvas.value!);
  }
}

async function onDrop(file: VirtualFile) {
  console.log('onDrop!!', file);
  onLoad(file);
}

const mode = ref<'drag' | 'draw' | 'measure'>('drag');
const dragging = ref(false);



function onScroll(event: WheelEvent) {
  event.preventDefault();
  // console.log('scroll', event.deltaY, event.offsetX, event.offsetY);
  const delta = -1 * event.deltaY / 2000;
  if (!canvasDisplay) {
    return;
  }
  canvasDisplay.scale = Math.min(Math.max(0.1, canvasDisplay.scale + delta), 10);

  if (canvas.value) {
    if (delta > 0) {
      const displayMousePosition = {
        x: ((event.offsetX / canvas.value!.width) - 0.5) * 2 * canvasDisplay.width,
        y: ((event.offsetY / canvas.value!.height) - 0.5) * 2 * canvasDisplay.height,
      };
      canvasDisplay.offsetX += displayMousePosition.x * delta;
      canvasDisplay.offsetY += displayMousePosition.y * delta;
    } else {
      canvasDisplay.offsetX -= closerToZero((canvasDisplay.width * Math.abs(delta)) * Math.sign(canvasDisplay.offsetX), canvasDisplay.offsetX);
      canvasDisplay.offsetY -= closerToZero((canvasDisplay.height * Math.abs(delta)) * Math.sign(canvasDisplay.offsetY), canvasDisplay.offsetY);
    }
  }
}

function showPointer(show: boolean) {
  pointerVisible.value = show;
  if (canvasDisplay && !show) {
    canvasDisplay.distanceMeasurement.pointer = undefined;
  }
}

function onMouseDown(event: MouseEvent) {
  window.getSelection()?.removeAllRanges();
  if (mode.value === 'drag') {
    dragging.value = true;
  }
  if (mode.value === 'measure') {
    if (canvasDisplay) {
      const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;
      canvasDisplay.distanceMeasurement.start = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale}
    }
  }
  window.addEventListener('mouseup', onMouseUp);
}

function onMouseUp(event: MouseEvent) {
  dragging.value = false;
  
  window.removeEventListener('mouseup', onMouseUp);
  if (mode.value === 'measure' && canvasDisplay) {
    canvasDisplay.distanceMeasurement.start = undefined;
  }
}
function onMouseMove(event: MouseEvent) {
  if (pointerVisible.value && canvasDisplay) {
    const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;
    if (canvasDisplay) {
      canvasDisplay.distanceMeasurement.pointer = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale};
    }
  }

  if (event.buttons === 0) {
    onMouseUp(event);
    return;
  }

  if (!canvasDisplay) {
    return;
  }

  const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;

  if (dragging.value) {
    canvasDisplay.offsetX -= event.movementX / mouseScale;
    canvasDisplay.offsetY -= event.movementY / mouseScale;
  }
  if (mode.value === 'measure') {
    if (canvasDisplay) {
      canvasDisplay.distanceMeasurement.end = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale};
    }
  }
}

function reset() {
  if (!canvasDisplay) {
    return;
  }
  canvasDisplay.offsetX = 0;
  canvasDisplay.offsetY = 0;
  canvasDisplay.scale = 1;
}

function onKeydown(event: KeyboardEvent) {
  if (event.key === 'Control') {
    showPointer(true);
  }
}

function onKeyup(event: KeyboardEvent) {
  if (event.key === 'Control') {
    showPointer(false);
  }
}

onMounted(() => {
  onLoad();
  canvasDisplay?.connectTarget(canvas.value!);
  window.addEventListener('reveal-screen', (event: CustomEvent) => {
    selectScreen(event.detail);
  });

  window.addEventListener('keydown', onKeydown);
  window.addEventListener('keyup', onKeyup);
  window.addEventListener('mousemove', onMouseMove);
});

onBeforeUnmount(() => {
  canvasDisplay?.disconnectTarget(canvas.value!);
  window.removeEventListener('keydown', onKeydown);
  window.removeEventListener('keyup', onKeyup);
  window.removeEventListener('mousemove', onMouseMove);
});

async function onLoad(file?: VirtualFile | File) {
  const meta = file;
  if (!canvasDisplay) {
    return;
  }
  if (!(file instanceof File) && file?.type === 'file') {
    file = await fs.download(file);
  } else {
    return;
  }
  console.log('onLoad', file, meta?.map?.width);
  // @ts-ignore
  const layer = new MapLayerDrawable(file, meta?.map?.width);
  await layer.preloadFile();
  canvasDisplay.mapLayer = layer;
};

</script>
<style lang="css">
.map-control {
  display: inline-block;
  border: 1px solid white;
  background: white;
  position: relative;
}
.map-control--over:before {
  content: 'Drop here';
  position: absolute;
  inset: 10px;
  border: 3px solid black;
}

</style>