<template>
  <div class="flex flex-wrap gap-3">
    <div v-for="(image, index) in modelValue" :key="index" class="h-20 w-20 p-4 bg-gray-300 bg-opacity-50 rounded text-center relative group cursor-move" draggable="true" @dragstart="dragStart($event, index)" @dragover.prevent @dragenter.prevent @drop="drop($event, index)">
      <img :src="image.url" class="max-w-full max-h-full object-contain pointer-events-none" alt="Uploaded image" @load="updateImageDimensions($event, index)" />
      <div v-if="imageDimensions[index]" class="absolute bottom-1 right-1 bg-black/50 text-white text-xs px-1 py-0.5 rounded transition-opacity font-default">{{ imageDimensions[index].width }}x{{ imageDimensions[index].height }}</div>
      <div class="absolute top-1 left-1 flex-row space-y-1">
        <button @click.stop="deleteImage(index)" class="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" aria-label="Delete image">
          <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
        <button @click.stop="openOffsetModal(index)" class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" aria-label="Scope image">
          <svg width="50px" height="50px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M8.29289 3.70711L1 11V15H5L12.2929 7.70711L8.29289 3.70711Z" fill="white" />
            <path d="M9.70711 2.29289L13.7071 6.29289L15.1716 4.82843C15.702 4.29799 16 3.57857 16 2.82843C16 1.26633 14.7337 0 13.1716 0C12.4214 0 11.702 0.297995 11.1716 0.828428L9.70711 2.29289Z" fill="white" />
          </svg>
        </button>
      </div>

      <Modal :is-modal-open="selectedImageIndex === index" :modal-width="300" :modal-height="210" :is-resizable="false" bg-style="none" @modal:close="closeOffsetModal">
        <template #modalHeader>
          <h3 class="m-0 font-medium shrink-0 text-white">Action offset ({{ selectedImageIndex }})</h3>
        </template>
        <template #modalBody>
          <div class="m-4">
            <form method="post" @submit.prevent="saveOffset(index)" class="inline">
              <div class="gap-2.5 flex flex-wrap">
                <div class="form-field-half">
                  <label for="offsetX">Offset X</label>
                  <input class="input-field max-w-64" v-model="tempOffset.x" name="offsetX" id="offsetX" type="number" />
                </div>
                <div class="form-field-half">
                  <label for="offsetY">Offset Y</label>
                  <input class="input-field max-w-64" v-model="tempOffset.y" name="offsetY" id="offsetY" type="number" />
                </div>
              </div>
              <button class="btn-cyan px-4 py-1.5 min-w-24" type="submit">Save</button>
            </form>
          </div>
        </template>
      </Modal>
    </div>
    <div class="h-20 w-20 p-4 bg-gray-200 bg-opacity-50 rounded justify-center items-center flex hover:cursor-pointer" @click="triggerFileInput" @drop.prevent="onDrop" @dragover.prevent>
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 invert" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
      </svg>
    </div>
  </div>
  <input type="file" ref="fileInput" @change="onFileChange" multiple accept="image/png" class="hidden" />
</template>

<script setup lang="ts">
import Modal from '@/components/utilities/Modal.vue'
import { ref, watch } from 'vue'

interface SpriteImage {
  url: string
  offset: {
    x: number
    y: number
  }
}

interface Props {
  modelValue: SpriteImage[]
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => []
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: SpriteImage[]): void
  (e: 'close'): void
  (e: 'tempOffsetChange', index: number, offset: { x: number; y: number }): void
}>()

const fileInput = ref<HTMLInputElement | null>(null)
const draggedIndex = ref<number | null>(null)
const selectedImageIndex = ref<number | null>(null)
const tempOffset = ref({ x: 0, y: 0 })

const triggerFileInput = () => {
  fileInput.value?.click()
}

const onFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files) {
    handleFiles(target.files)
  }
}

const onDrop = (event: DragEvent) => {
  if (event.dataTransfer?.files) {
    handleFiles(event.dataTransfer.files)
  }
}

const handleFiles = (files: FileList) => {
  Array.from(files).forEach((file) => {
    if (!file.type.startsWith('image/')) {
      return
    }

    const reader = new FileReader()
    reader.onload = (e) => {
      if (typeof e.target?.result === 'string') {
        const newImage: SpriteImage = {
          url: e.target.result,
          offset: { x: 0, y: 0 }
        }
        updateImages([...props.modelValue, newImage])
      }
    }
    reader.readAsDataURL(file)
  })
}

const updateImages = (newImages: SpriteImage[]) => {
  emit('update:modelValue', newImages)
}

const deleteImage = (index: number) => {
  const newImages = [...props.modelValue]
  newImages.splice(index, 1)
  updateImages(newImages)
}

const dragStart = (event: DragEvent, index: number) => {
  draggedIndex.value = index
  if (event.dataTransfer) {
    event.dataTransfer.effectAllowed = 'move'
    event.dataTransfer.dropEffect = 'move'
  }
}

const drop = (event: DragEvent, dropIndex: number) => {
  event.preventDefault()
  if (draggedIndex.value !== null && draggedIndex.value !== dropIndex) {
    const newImages = [...props.modelValue]
    const [reorderedItem] = newImages.splice(draggedIndex.value, 1)
    newImages.splice(dropIndex, 0, reorderedItem)
    updateImages(newImages)
  }
  draggedIndex.value = null
}

const openOffsetModal = (index: number) => {
  selectedImageIndex.value = index
  tempOffset.value = { ...props.modelValue[index].offset }
}

const closeOffsetModal = () => {
  selectedImageIndex.value = null
}

const saveOffset = (index: number) => {
  const newImages = [...props.modelValue]
  newImages[index] = {
    ...newImages[index],
    offset: { ...tempOffset.value }
  }
  updateImages(newImages)
  closeOffsetModal()
}

const onOffsetChange = () => {
  if (selectedImageIndex.value !== null) {
    emit('tempOffsetChange', selectedImageIndex.value, tempOffset.value)
  }
}

watch(tempOffset, onOffsetChange, { deep: true })

const imageDimensions = ref<{ [key: number]: { width: number; height: number } }>({})

const updateImageDimensions = (event: Event, index: number) => {
  const img = event.target as HTMLImageElement
  imageDimensions.value[index] = {
    width: img.naturalWidth,
    height: img.naturalHeight
  }
}
</script>
