<template>
  <Modal :is-modal-open="isModalOpen" :modal-width="700" :modal-height="330" bg-style="none" @modal:close="closeModal">
    <template #modalHeader>
      <h3 class="m-0 font-medium shrink-0 text-white">View sprite</h3>
    </template>
    <template #modalBody>
      <div class="m-4 flex gap-8">
        <div class="relative">
          <div
            class="sprite-container bg-gray-800"
            :style="{
              width: `${maxWidth}px`,
              height: `${maxHeight}px`,
              position: 'relative',
              overflow: 'hidden'
            }"
          >
            <img
              v-for="(sprite, index) in spritesWithTempOffset"
              :key="index"
              :src="sprite.url"
              alt="Sprite"
              :style="{
                position: 'absolute',
                left: `${sprite.offset?.x || 0}px`,
                bottom: `${sprite.offset?.y || 0}px`,
                display: currentFrame === index ? 'block' : 'none',
                transform: `scale(${zoomLevel / 100})`,
                transformOrigin: 'bottom left'
              }"
              @load="updateContainerSize"
            />
          </div>
        </div>
        <div class="flex flex-col justify-center gap-8 flex-1">
          <div class="flex flex-col">
            <label class="block mb-2 text-white">Frame Rate: {{ frameRate }} FPS</label>
            <input type="range" v-model.number="localFrameRate" min="0" max="60" step="1" class="w-full accent-cyan-500" @input="updateFrameRate" />
          </div>
          <div class="flex flex-col">
            <label class="block mb-2 text-white">Frame: {{ currentFrame + 1 }} of {{ sprites.length }}</label>
            <input type="range" v-model.number="currentFrame" :min="0" :max="sprites.length - 1" step="1" class="w-full accent-cyan-500" @input="stopAnimation" />
          </div>
          <div class="flex flex-col">
            <label class="block mb-2 text-white">Zoom: {{ zoomLevel }}%</label>
            <input type="range" v-model.number="zoomLevel" min="10" max="200" step="10" class="w-full accent-cyan-500" />
          </div>
        </div>
      </div>
    </template>
  </Modal>
</template>

<script setup lang="ts">
import type { SpriteImage } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'

const props = defineProps<{
  sprites: SpriteImage[]
  frameRate: number
  isModalOpen?: boolean
  tempOffsetIndex?: number
  tempOffset?: { x: number; y: number }
}>()

const emit = defineEmits<{
  (e: 'update:frameRate', value: number): void
  (e: 'update:isModalOpen', value: boolean): void
}>()

const currentFrame = ref(0)
const maxWidth = ref(250)
const maxHeight = ref(250)
const localFrameRate = ref(props.frameRate)
const zoomLevel = ref(100)
let animationInterval: number | null = null

const spritesWithTempOffset = computed(() => {
  return props.sprites.map((sprite, index) => {
    if (index === props.tempOffsetIndex && props.tempOffset) {
      return { ...sprite, offset: props.tempOffset }
    }
    return sprite
  })
})

function updateContainerSize(event: Event) {
  const img = event.target as HTMLImageElement
  maxWidth.value = Math.max(maxWidth.value, img.naturalWidth)
  maxHeight.value = Math.max(maxHeight.value, img.naturalHeight)
}

function updateAnimation() {
  stopAnimation()
  if (props.frameRate <= 0 || props.sprites.length === 0) {
    currentFrame.value = 0
    return
  }

  animationInterval = window.setInterval(() => {
    currentFrame.value = (currentFrame.value + 1) % props.sprites.length
  }, 1000 / props.frameRate)
}

function stopAnimation() {
  if (animationInterval) {
    clearInterval(animationInterval)
    animationInterval = null
  }
}

function updateFrameRate() {
  emit('update:frameRate', localFrameRate.value)
}

function closeModal() {
  emit('update:isModalOpen', false)
}

watch(
  () => props.frameRate,
  (newValue) => {
    localFrameRate.value = newValue
    updateAnimation()
  },
  { immediate: true }
)

watch(() => props.sprites, updateAnimation, { immediate: true })

onMounted(() => {
  updateAnimation()
})

onUnmounted(() => {
  stopAnimation()
})
</script>

<style scoped>
.sprite-container {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}
</style>
