<template>
  <div
    class="h-full flex flex-col bg-canvas rounded-card border border-line overflow-hidden"
    data-testid="scan-viewer"
  >
    <!-- Toolbar — light chrome, no decorative overlays on the page -->
    <div
      class="flex flex-wrap items-center gap-0.5 sm:gap-1 px-2 sm:px-3 py-2 bg-surface border-b border-line text-sm text-ink shrink-0"
      data-testid="scan-viewer-toolbar"
    >
      <button
        type="button"
        class="scan-toolbar-btn"
        title="Zoom out"
        :disabled="!url"
        @click="zoomOut"
      >
        −
      </button>
      <button
        type="button"
        class="scan-toolbar-btn"
        title="Zoom in"
        :disabled="!url"
        @click="zoomIn"
      >
        +
      </button>
      <button
        type="button"
        class="scan-toolbar-btn"
        title="Fit width"
        :disabled="!url"
        data-testid="scan-fit-width"
        @click="fitWidth"
      >
        Fit width
      </button>
      <button
        type="button"
        class="scan-toolbar-btn"
        title="Reset zoom"
        :disabled="!url"
        @click="resetZoom"
      >
        1:1
      </button>
      <button
        type="button"
        class="scan-toolbar-btn"
        title="Rotate 90°"
        :disabled="!url"
        @click="rotateCw"
      >
        Rotate
      </button>
      <span class="ml-auto text-ink-secondary text-xs tabular-nums">
        {{ url ? `${Math.round(scale * 100)}%` : '' }}
      </span>
    </div>

    <!-- Document surface -->
    <div
      ref="viewerContainer"
      class="flex-1 min-h-0 overflow-auto bg-[#E8ECF1]"
      :class="url && !loading && !error ? 'cursor-grab active:cursor-grabbing' : ''"
      @mousedown="startPan"
      @mousemove="pan"
      @mouseup="stopPan"
      @mouseleave="stopPan"
      @wheel.prevent="onWheel"
    >
      <div v-if="loading" class="flex h-full items-center justify-center p-8">
        <SkeletonBlock
          variant="block"
          height="min(70vh, 640px)"
          width="min(100%, 480px)"
          class="max-w-full shadow-page bg-surface"
        />
      </div>

      <div v-else-if="error" class="flex min-h-[10rem] items-center justify-center p-4 sm:p-6">
        <InlineError
          class="max-w-md w-full"
          title="Could not load document"
          :message="error"
          preserved="Your form draft was not affected."
          retry-label="Retry"
          @retry="$emit('retry')"
        />
      </div>

      <div
        v-else-if="url"
        class="p-6 inline-block min-w-full"
      >
        <div
          :style="{
            transform: `translate(${panX}px, ${panY}px) scale(${scale}) rotate(${rotation}deg)`,
            transformOrigin: 'top left',
            transition: isPanning ? 'none' : 'transform 0.15s ease-out',
          }"
        >
          <!-- PDF/image from same-origin blob URL (avoids cross-origin MinIO iframe issues) -->
          <iframe
            v-if="isPdf"
            :src="url"
            class="scan-page w-[800px] h-[1100px] bg-white"
            frameborder="0"
            title="Scanned document"
          />
          <img
            v-else
            :src="url"
            class="scan-page max-w-none bg-white"
            draggable="false"
            alt="Scanned document"
            @load="onImageLoad"
          />
        </div>
      </div>

      <EmptyState
        v-else
        title="No document available"
        description="The source scan will appear here when the batch document loads."
        class="h-full"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import SkeletonBlock from './SkeletonBlock.vue'
import InlineError from './InlineError.vue'
import EmptyState from './EmptyState.vue'

const props = withDefaults(
  defineProps<{
    url?: string | null
    loading?: boolean
    error?: string | null
  }>(),
  {
    url: null,
    loading: false,
    error: null,
  }
)

defineEmits<{
  (e: 'retry'): void
}>()

const isPdf = computed(() => {
  if (!props.url) return false
  const lower = props.url.toLowerCase()
  return lower.includes('.pdf') || lower.includes('application/pdf')
})

const scale = ref(1)
const rotation = ref(0)
const panX = ref(0)
const panY = ref(0)
const isPanning = ref(false)
const lastX = ref(0)
const lastY = ref(0)
const viewerContainer = ref<HTMLElement | null>(null)
const naturalPageWidth = ref(800)

function zoomIn() {
  scale.value = Math.min(scale.value + 0.25, 5)
}
function zoomOut() {
  scale.value = Math.max(scale.value - 0.25, 0.25)
}
function resetZoom() {
  scale.value = 1
  panX.value = 0
  panY.value = 0
  rotation.value = 0
}
function rotateCw() {
  rotation.value = (rotation.value + 90) % 360
}

function fitWidth() {
  const container = viewerContainer.value
  if (!container) return
  const padding = 48 // matches p-6
  const available = Math.max(container.clientWidth - padding, 120)
  scale.value = Math.min(Math.max(available / naturalPageWidth.value, 0.25), 5)
  panX.value = 0
  panY.value = 0
}

function onWheel(e: WheelEvent) {
  if (!props.url || props.loading || props.error) return
  if (e.deltaY < 0) zoomIn()
  else zoomOut()
}

function startPan(e: MouseEvent) {
  if (!props.url || props.loading || props.error) return
  if ((e.target as HTMLElement)?.closest('button')) return
  isPanning.value = true
  lastX.value = e.clientX
  lastY.value = e.clientY
}

function pan(e: MouseEvent) {
  if (!isPanning.value) return
  panX.value += e.clientX - lastX.value
  panY.value += e.clientY - lastY.value
  lastX.value = e.clientX
  lastY.value = e.clientY
}

function stopPan() {
  isPanning.value = false
}

function onImageLoad(e: Event) {
  const img = e.target as HTMLImageElement
  if (img.naturalWidth > 0) {
    naturalPageWidth.value = img.naturalWidth
  }
  scale.value = 1
  panX.value = 0
  panY.value = 0
  nextTick(() => fitWidth())
}

watch(
  () => props.url,
  (url) => {
    if (!url) return
    if (isPdf.value) {
      naturalPageWidth.value = 800
      nextTick(() => fitWidth())
    }
  }
)
</script>

<style scoped>
.scan-toolbar-btn {
  @apply px-2 py-1 rounded-control text-ink hover:bg-canvas
         disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent
         transition-colors;
}
.scan-page {
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 4px 16px rgba(16, 24, 40, 0.08);
}
</style>
