<template>
  <div class="spritesheet-preview w-full">
    <!-- Controls Container -->
    <div class="bg-white rounded-lg border border-gray-200 p-4">
      <div class="flex flex-col gap-4 sm:flex-row sm:flex-wrap">
        <!-- Playback Controls -->
        <div class="flex items-center gap-2">
          <div class="space-y-2">
            <button @click="togglePlayback" class="flex items-center gap-1.5 bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md transition-colors w-full cursor-pointer">
              <span v-if="isPlaying" class="flex items-center gap-1.5">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
                  <path fill-rule="evenodd" d="M6.75 5.25a.75.75 0 01.75-.75H9a.75.75 0 01.75.75v13.5a.75.75 0 01-.75.75H7.5a.75.75 0 01-.75-.75V5.25zm7.5 0A.75.75 0 0115 4.5h1.5a.75.75 0 01.75.75v13.5a.75.75 0 01-.75.75H15a.75.75 0 01-.75-.75V5.25z" clip-rule="evenodd" />
                </svg>
                <span class="hidden sm:inline">Pause</span>
              </span>
              <span v-else class="flex items-center gap-1.5">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5">
                  <path fill-rule="evenodd" d="M4.5 5.653c0-1.426 1.529-2.33 2.779-1.643l11.54 6.348c1.295.712 1.295 2.573 0 3.285L7.28 19.991c-1.25.687-2.779-.217-2.779-1.643V5.653z" clip-rule="evenodd" />
                </svg>
                <span class="hidden sm:inline">Play</span>
              </span>
            </button>

            <div class="flex items-center gap-1">
              <button @click="previousFrame" class="bg-gray-200 hover:bg-gray-300 p-2 rounded-md transition-colors duration-200 w-full cursor-pointer" :disabled="isPlaying" :class="{ 'opacity-50 cursor-not-allowed': isPlaying }">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5 mx-auto">
                  <path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 01.75.75v12.06l4.72-4.72a.75.75 0 111.06 1.06l-6 6a.75.75 0 01-1.06 0l-6-6a.75.75 0 011.06-1.06l4.72 4.72V5.97a.75.75 0 01.75-.75z" clip-rule="evenodd" transform="rotate(90 12 12)" />
                </svg>
              </button>
              <button @click="nextFrame" class="bg-gray-200 hover:bg-gray-300 p-2 rounded-md transition-colors duration-200 w-full cursor-pointer" :disabled="isPlaying" :class="{ 'opacity-50 cursor-not-allowed': isPlaying }">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-5 h-5 mx-auto">
                  <path fill-rule="evenodd" d="M11.78 5.22a.75.75 0 01.75.75v12.06l4.72-4.72a.75.75 0 111.06 1.06l-6 6a.75.75 0 01-1.06 0l-6-6a.75.75 0 011.06-1.06l4.72 4.72V5.97a.75.75 0 01.75-.75z" clip-rule="evenodd" transform="rotate(-90 12 12)" />
                </svg>
              </button>
            </div>

            <!-- Checkboxes -->
            <div class="flex flex-wrap gap-4 items-center">
              <label class="flex items-center gap-2 cursor-pointer">
                <input type="checkbox" v-model="isDraggable" class="w-4 h-4 text-blue-500 focus:ring-blue-400 rounded border-gray-300" />
                <span class="text-sm whitespace-nowrap">Reposition</span>
              </label>

              <label class="flex items-center gap-2 cursor-pointer">
                <input type="checkbox" v-model="showAllSprites" class="w-4 h-4 text-blue-500 focus:ring-blue-400 rounded border-gray-300" />
                <span class="text-sm whitespace-nowrap">Show all sprites</span>
              </label>
            </div>

            <div v-if="showAllSprites" class="w-full">
              <label class="block text-sm font-medium text-gray-700 mb-2">Hide frames</label>
              <select multiple v-model="hiddenFrames" class="w-full rounded-md border border-gray-300 shadow-sm px-3 py-2 focus:ring-blue-500 focus:border-blue-500" size="4">
                <option v-for="(sprite, index) in props.sprites" :key="sprite.id" :value="index" class="py-1">Frame {{ index + 1 }}</option>
              </select>
            </div>
          </div>
        </div>

        <!-- Frame Controls -->
        <div class="flex-1 min-w-[200px] space-y-6">
          <!-- Frame Navigation -->
          <div class="flex items-center gap-2">
            <span class="text-sm font-medium w-30">Frame {{ currentFrameIndex + 1 }}/{{ totalFrames }}</span>
            <input type="range" min="0" :max="totalFrames - 1" v-model.number="currentFrameIndex" class="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500" :disabled="isPlaying" :class="{ 'opacity-50': isPlaying }" />
          </div>

          <!-- FPS Control -->
          <div class="flex items-center gap-2">
            <span class="text-sm font-medium w-30">FPS: {{ fps }}</span>
            <input type="range" min="1" max="60" v-model.number="fps" class="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500" />
          </div>

          <!-- Zoom Control -->
          <div class="flex items-center gap-2">
            <span class="text-sm font-medium w-30">{{ Math.round(zoom * 100) }}%</span>
            <input type="range" min="0.5" max="5" step="0.1" v-model.number="zoom" class="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500" />
          </div>
        </div>
      </div>
    </div>

    <div class="mt-3 relative bg-gray-50 border border-gray-300 rounded-lg mb-6 overflow-auto min-h-[520px] shadow-sm hover:shadow-md transition-shadow duration-200">
      <canvas
        ref="previewCanvasRef"
        @mousedown="startDrag"
        @mousemove="drag"
        @mouseup="stopDrag"
        @mouseleave="stopDrag"
        @touchstart="handleTouchStart"
        @touchmove="handleTouchMove"
        @touchend="stopDrag"
        class="block"
        :class="{ 'cursor-move': isDraggable }"
        :style="{ transform: `scale(${zoom})`, transformOrigin: 'top left' }"
      >
      </canvas>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { ref, onMounted, watch, onUnmounted, computed } from 'vue';

  interface Sprite {
    id: string;
    img: HTMLImageElement;
    width: number;
    height: number;
    x: number;
    y: number;
  }

  const props = defineProps<{
    sprites: Sprite[];
    columns: number;
  }>();

  const emit = defineEmits<{
    (e: 'updateSprite', id: string, x: number, y: number): void;
  }>();

  const previewCanvasRef = ref<HTMLCanvasElement | null>(null);
  const ctx = ref<CanvasRenderingContext2D | null>(null);

  // Preview state
  const currentFrameIndex = ref(0);
  const isPlaying = ref(false);
  const fps = ref(12);
  const zoom = ref(1);
  const isDraggable = ref(false);
  const showAllSprites = ref(false);
  const animationFrameId = ref<number | null>(null);
  const lastFrameTime = ref(0);

  // Dragging state
  const isDragging = ref(false);
  const activeSpriteId = ref<string | null>(null);
  const dragStartX = ref(0);
  const dragStartY = ref(0);
  const spritePosBeforeDrag = ref({ x: 0, y: 0 });

  // Computed properties
  const totalFrames = computed(() => props.sprites.length);

  // Add this after other refs
  const hiddenFrames = ref<number[]>([]);

  // Canvas drawing
  const calculateMaxDimensions = () => {
    let maxWidth = 0;
    let maxHeight = 0;

    props.sprites.forEach(sprite => {
      maxWidth = Math.max(maxWidth, sprite.width);
      maxHeight = Math.max(maxHeight, sprite.height);
    });

    return { maxWidth, maxHeight };
  };

  const drawPreviewCanvas = () => {
    if (!previewCanvasRef.value || !ctx.value || props.sprites.length === 0) return;

    const currentSprite = props.sprites[currentFrameIndex.value];
    if (!currentSprite) return;

    const { maxWidth, maxHeight } = calculateMaxDimensions();

    // Set canvas size to just fit one sprite cell
    previewCanvasRef.value.width = maxWidth;
    previewCanvasRef.value.height = maxHeight;

    // Clear canvas
    ctx.value.clearRect(0, 0, previewCanvasRef.value.width, previewCanvasRef.value.height);

    // Draw grid background (cell)
    ctx.value.fillStyle = '#f9fafb';
    ctx.value.fillRect(0, 0, maxWidth, maxHeight);

    // Draw background grid (checkerboard pattern for transparency)
    const cellSize = 10;
    ctx.value.fillStyle = '#e5e7eb';

    for (let x = 0; x < maxWidth; x += cellSize) {
      for (let y = 0; y < maxHeight; y += cellSize) {
        if ((x / cellSize + y / cellSize) % 2 === 0) {
          ctx.value.fillRect(x, y, cellSize, cellSize);
        }
      }
    }

    // Apply pixel art optimization
    ctx.value.imageSmoothingEnabled = false;

    // Draw all sprites with transparency if enabled
    if (showAllSprites.value && props.sprites.length > 1) {
      ctx.value.globalAlpha = 0.3;
      props.sprites.forEach((sprite, index) => {
        if (index !== currentFrameIndex.value && !hiddenFrames.value.includes(index)) {
          ctx.value?.drawImage(sprite.img, sprite.x, sprite.y);
        }
      });
      ctx.value.globalAlpha = 1.0;
    }

    // Draw current sprite
    ctx.value.drawImage(currentSprite.img, currentSprite.x, currentSprite.y);

    // Draw cell border
    ctx.value.strokeStyle = '#e5e7eb';
    ctx.value.lineWidth = 1;
    ctx.value.strokeRect(0, 0, maxWidth, maxHeight);
  };

  // Animation control
  const togglePlayback = () => {
    isPlaying.value = !isPlaying.value;

    if (isPlaying.value) {
      startAnimation();
    } else {
      stopAnimation();
    }
  };

  const startAnimation = () => {
    lastFrameTime.value = performance.now();
    animateFrame();
  };

  const stopAnimation = () => {
    if (animationFrameId.value !== null) {
      cancelAnimationFrame(animationFrameId.value);
      animationFrameId.value = null;
    }
  };

  const animateFrame = () => {
    const now = performance.now();
    const elapsed = now - lastFrameTime.value;
    const frameTime = 1000 / fps.value;

    if (elapsed >= frameTime) {
      lastFrameTime.value = now - (elapsed % frameTime);
      nextFrame();
    }

    animationFrameId.value = requestAnimationFrame(animateFrame);
  };

  const nextFrame = () => {
    if (props.sprites.length === 0) return;

    currentFrameIndex.value = (currentFrameIndex.value + 1) % props.sprites.length;
    drawPreviewCanvas();
  };

  const previousFrame = () => {
    if (props.sprites.length === 0) return;

    currentFrameIndex.value = (currentFrameIndex.value - 1 + props.sprites.length) % props.sprites.length;
    drawPreviewCanvas();
  };

  // Drag functionality
  const startDrag = (event: MouseEvent) => {
    if (!isDraggable.value || !previewCanvasRef.value) return;

    const rect = previewCanvasRef.value.getBoundingClientRect();
    const scaleX = previewCanvasRef.value.width / (rect.width / zoom.value);
    const scaleY = previewCanvasRef.value.height / (rect.height / zoom.value);

    const mouseX = ((event.clientX - rect.left) / zoom.value) * scaleX;
    const mouseY = ((event.clientY - rect.top) / zoom.value) * scaleY;

    const sprite = props.sprites[currentFrameIndex.value];

    // Check if click is on sprite
    if (sprite && mouseX >= sprite.x && mouseX <= sprite.x + sprite.width && mouseY >= sprite.y && mouseY <= sprite.y + sprite.height) {
      isDragging.value = true;
      activeSpriteId.value = sprite.id;
      dragStartX.value = mouseX;
      dragStartY.value = mouseY;
      spritePosBeforeDrag.value = { x: sprite.x, y: sprite.y };
    }
  };

  const drag = (event: MouseEvent) => {
    if (!isDragging.value || !activeSpriteId.value || !previewCanvasRef.value) return;

    const rect = previewCanvasRef.value.getBoundingClientRect();
    const scaleX = previewCanvasRef.value.width / (rect.width / zoom.value);
    const scaleY = previewCanvasRef.value.height / (rect.height / zoom.value);

    const mouseX = ((event.clientX - rect.left) / zoom.value) * scaleX;
    const mouseY = ((event.clientY - rect.top) / zoom.value) * scaleY;

    const deltaX = mouseX - dragStartX.value;
    const deltaY = mouseY - dragStartY.value;

    const sprite = props.sprites[currentFrameIndex.value];
    if (!sprite || sprite.id !== activeSpriteId.value) return;

    const { maxWidth, maxHeight } = calculateMaxDimensions();

    // Calculate new position with constraints
    let newX = spritePosBeforeDrag.value.x + deltaX;
    let newY = spritePosBeforeDrag.value.y + deltaY;

    // Constrain movement within cell
    newX = Math.max(0, Math.min(maxWidth - sprite.width, newX));
    newY = Math.max(0, Math.min(maxHeight - sprite.height, newY));

    emit('updateSprite', activeSpriteId.value, newX, newY);
    drawPreviewCanvas();
  };

  const stopDrag = () => {
    isDragging.value = false;
    activeSpriteId.value = null;
  };

  const handleTouchStart = (event: TouchEvent) => {
    if (event.touches.length === 1) {
      const touch = event.touches[0];
      const mouseEvent = new MouseEvent('mousedown', {
        clientX: touch.clientX,
        clientY: touch.clientY,
      });
      startDrag(mouseEvent);
    }
  };

  const handleTouchMove = (event: TouchEvent) => {
    if (event.touches.length === 1) {
      const touch = event.touches[0];
      const mouseEvent = new MouseEvent('mousemove', {
        clientX: touch.clientX,
        clientY: touch.clientY,
      });
      drag(mouseEvent);
    }
  };

  // Lifecycle hooks
  onMounted(() => {
    if (previewCanvasRef.value) {
      ctx.value = previewCanvasRef.value.getContext('2d');
      drawPreviewCanvas();
    }
  });

  onUnmounted(() => {
    stopAnimation();
  });

  // Watchers
  watch(() => props.sprites, drawPreviewCanvas, { deep: true });
  watch(currentFrameIndex, drawPreviewCanvas);
  watch(zoom, drawPreviewCanvas);
  watch(isDraggable, drawPreviewCanvas);
  watch(showAllSprites, drawPreviewCanvas);
  watch(hiddenFrames, drawPreviewCanvas);

  // Initial draw
  if (props.sprites.length > 0) {
    drawPreviewCanvas();
  }
</script>

<style scoped>
  /* Custom styling for range inputs */
  input[type='range']::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #3b82f6;
    cursor: pointer;
  }

  input[type='range']::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #3b82f6;
    cursor: pointer;
    border: none;
  }
</style>
