<template>
  <div class="image-viewer w-full h-full bg-gray-100 dark:bg-gray-900 relative overflow-hidden">
    <!-- Image Container -->
    <div 
      ref="imageContainer"
      class="w-full h-full flex items-center justify-center overflow-auto"
      @wheel="handleWheel"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      @mouseleave="handleMouseUp"
    >
      <div
        class="relative"
        :style="{
          transform: `scale(${currentZoom / 100}) translate(${panX}px, ${panY}px)`,
          transformOrigin: 'center center',
          transition: isAnimating ? 'transform 0.3s ease-out' : 'none'
        }"
      >
        <img
          ref="imageElement"
          :src="imageUrl"
          :alt="document.name"
          class="max-w-none block select-none"
          @load="handleImageLoad"
          @error="handleImageError"
          @dragstart.prevent
        />
      </div>
    </div>

    <!-- Loading State -->
    <div 
      v-if="isLoading"
      class="absolute inset-0 flex items-center justify-center bg-white bg-opacity-90 dark:bg-gray-900 dark:bg-opacity-90"
    >
      <div class="text-center">
        <Icon name="mdi:loading" class="w-8 h-8 animate-spin text-blue-600 mx-auto mb-2" />
        <p class="text-gray-600 dark:text-gray-400">Loading image...</p>
      </div>
    </div>

    <!-- Error State -->
    <div 
      v-if="hasError"
      class="absolute inset-0 flex items-center justify-center bg-white bg-opacity-90 dark:bg-gray-900 dark:bg-opacity-90"
    >
      <div class="text-center">
        <Icon name="mdi:image-broken" class="w-16 h-16 text-red-400 mx-auto mb-2" />
        <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">Failed to Load Image</h3>
        <p class="text-gray-600 dark:text-gray-400">The image could not be displayed.</p>
      </div>
    </div>

    <!-- Image Info Overlay -->
    <div 
      v-if="showImageInfo && !isLoading && !hasError"
      class="absolute top-4 left-4 bg-black bg-opacity-70 text-white px-3 py-2 rounded-lg text-sm"
    >
      <div>{{ document.name }}</div>
      <div v-if="imageMetadata.dimensions">{{ imageMetadata.dimensions }}</div>
      <div v-if="imageMetadata.fileSize">{{ imageMetadata.fileSize }}</div>
    </div>

    <!-- Zoom Controls -->
    <div 
      v-if="!isLoading && !hasError"
      class="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-70 rounded-full px-4 py-2 flex items-center space-x-2"
    >
      <button
        @click="zoomOut"
        :disabled="currentZoom <= 25"
        class="p-1 text-white hover:bg-white hover:bg-opacity-20 rounded disabled:opacity-50"
        title="Zoom Out"
      >
        <Icon name="mdi:magnify-minus" class="w-4 h-4" />
      </button>
      
      <span class="text-white text-sm min-w-12 text-center">
        {{ Math.round(currentZoom) }}%
      </span>
      
      <button
        @click="zoomIn"
        :disabled="currentZoom >= 500"
        class="p-1 text-white hover:bg-white hover:bg-opacity-20 rounded disabled:opacity-50"
        title="Zoom In"
      >
        <Icon name="mdi:magnify-plus" class="w-4 h-4" />
      </button>
      
      <div class="w-px h-4 bg-white bg-opacity-30 mx-1"></div>
      
      <button
        @click="fitToScreen"
        class="p-1 text-white hover:bg-white hover:bg-opacity-20 rounded"
        title="Fit to Screen"
      >
        <Icon name="mdi:fit-to-screen" class="w-4 h-4" />
      </button>
      
      <button
        @click="actualSize"
        class="p-1 text-white hover:bg-white hover:bg-opacity-20 rounded"
        title="Actual Size"
      >
        <Icon name="mdi:magnify" class="w-4 h-4" />
      </button>
      
      <button
        @click="toggleImageInfo"
        class="p-1 text-white hover:bg-white hover:bg-opacity-20 rounded"
        title="Toggle Info"
      >
        <Icon name="mdi:information" class="w-4 h-4" />
      </button>
    </div>

    <!-- Pan Hint -->
    <div 
      v-if="currentZoom > 100 && !isLoading && !hasError"
      class="absolute top-4 right-4 bg-black bg-opacity-70 text-white px-3 py-1 rounded text-xs"
    >
      Drag to pan
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';

const props = defineProps({
  document: {
    type: Object,
    required: true
  },
  zoom: {
    type: Number,
    default: 100
  }
});

const emit = defineEmits([
  'zoom-changed'
]);

// State
const isLoading = ref(true);
const hasError = ref(false);
const currentZoom = ref(props.zoom);
const showImageInfo = ref(false);
const isAnimating = ref(false);

// Pan state
const panX = ref(0);
const panY = ref(0);
const isPanning = ref(false);
const lastPanX = ref(0);
const lastPanY = ref(0);

// Image metadata
const imageMetadata = ref({
  dimensions: null,
  fileSize: null,
  naturalWidth: 0,
  naturalHeight: 0
});

// Refs
const imageContainer = ref(null);
const imageElement = ref(null);

// Computed
const imageUrl = computed(() => {
  // In a real implementation, this would be the actual image URL
  return `/api/documents/${props.document.id}/preview`;
});

// Methods
const handleImageLoad = () => {
  isLoading.value = false;
  hasError.value = false;
  
  if (imageElement.value) {
    const img = imageElement.value;
    imageMetadata.value = {
      dimensions: `${img.naturalWidth} × ${img.naturalHeight}`,
      fileSize: props.document.size,
      naturalWidth: img.naturalWidth,
      naturalHeight: img.naturalHeight
    };
    
    // Auto-fit to screen on first load
    nextTick(() => {
      fitToScreen();
    });
  }
};

const handleImageError = () => {
  isLoading.value = false;
  hasError.value = true;
};

const zoomIn = () => {
  const newZoom = Math.min(currentZoom.value * 1.25, 500);
  setZoom(newZoom);
};

const zoomOut = () => {
  const newZoom = Math.max(currentZoom.value / 1.25, 25);
  setZoom(newZoom);
};

const setZoom = (zoom, animate = true) => {
  if (animate) {
    isAnimating.value = true;
    setTimeout(() => {
      isAnimating.value = false;
    }, 300);
  }
  
  currentZoom.value = zoom;
  emit('zoom-changed', zoom);
  
  // Reset pan when zooming
  if (zoom <= 100) {
    panX.value = 0;
    panY.value = 0;
  }
};

const fitToScreen = () => {
  if (!imageElement.value || !imageContainer.value) return;
  
  const container = imageContainer.value;
  const img = imageElement.value;
  
  const containerWidth = container.clientWidth;
  const containerHeight = container.clientHeight;
  const imageWidth = img.naturalWidth;
  const imageHeight = img.naturalHeight;
  
  const scaleX = containerWidth / imageWidth;
  const scaleY = containerHeight / imageHeight;
  const scale = Math.min(scaleX, scaleY, 1) * 0.9; // 90% to leave some margin
  
  setZoom(scale * 100);
  panX.value = 0;
  panY.value = 0;
};

const actualSize = () => {
  setZoom(100);
  panX.value = 0;
  panY.value = 0;
};

const toggleImageInfo = () => {
  showImageInfo.value = !showImageInfo.value;
};

// Mouse handling for pan
const handleMouseDown = (event) => {
  if (currentZoom.value > 100) {
    isPanning.value = true;
    lastPanX.value = event.clientX;
    lastPanY.value = event.clientY;
    event.preventDefault();
  }
};

const handleMouseMove = (event) => {
  if (isPanning.value && currentZoom.value > 100) {
    const deltaX = event.clientX - lastPanX.value;
    const deltaY = event.clientY - lastPanY.value;
    
    panX.value += deltaX;
    panY.value += deltaY;
    
    lastPanX.value = event.clientX;
    lastPanY.value = event.clientY;
    
    event.preventDefault();
  }
};

const handleMouseUp = () => {
  isPanning.value = false;
};

// Wheel handling for zoom
const handleWheel = (event) => {
  if (event.ctrlKey || event.metaKey) {
    event.preventDefault();
    
    const delta = event.deltaY > 0 ? -10 : 10;
    const newZoom = Math.max(25, Math.min(500, currentZoom.value + delta));
    setZoom(newZoom, false);
  }
};

// Keyboard shortcuts
const handleKeydown = (event) => {
  switch (event.key) {
    case '+':
    case '=':
      if (event.ctrlKey || event.metaKey) {
        event.preventDefault();
        zoomIn();
      }
      break;
    case '-':
      if (event.ctrlKey || event.metaKey) {
        event.preventDefault();
        zoomOut();
      }
      break;
    case '0':
      if (event.ctrlKey || event.metaKey) {
        event.preventDefault();
        fitToScreen();
      }
      break;
    case '1':
      if (event.ctrlKey || event.metaKey) {
        event.preventDefault();
        actualSize();
      }
      break;
    case 'i':
      if (event.ctrlKey || event.metaKey) {
        event.preventDefault();
        toggleImageInfo();
      }
      break;
  }
};

// Watchers
watch(() => props.zoom, (newZoom) => {
  if (newZoom !== currentZoom.value) {
    setZoom(newZoom, false);
  }
});

watch(() => props.document, () => {
  // Reset state when document changes
  isLoading.value = true;
  hasError.value = false;
  currentZoom.value = 100;
  panX.value = 0;
  panY.value = 0;
  showImageInfo.value = false;
});

// Lifecycle
onMounted(() => {
  document.addEventListener('keydown', handleKeydown);
});

onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown);
});
</script>

<style scoped>
.image-viewer {
  cursor: grab;
}

.image-viewer.panning {
  cursor: grabbing;
}

/* Prevent text selection during panning */
.image-viewer * {
  user-select: none;
}

/* Custom scrollbars */
.image-viewer::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.image-viewer::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.1);
}

.image-viewer::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.3);
  border-radius: 4px;
}

.image-viewer::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.5);
}

/* Animation for smooth zooming */
.zoom-transition {
  transition: transform 0.3s ease-out;
}

/* Loading animation */
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.animate-spin {
  animation: spin 1s linear infinite;
}
</style> 