<script setup>
import { ref, onMounted } from 'vue'
const props = defineProps({
  src: { type: String, required: true },
  outputWidth: { type: Number, default: 440 },
  outputHeight: { type: Number, default: 290 },
  initialTransform: { type: Object, default: null },
})
const emit = defineEmits(["apply", "cancel"]);

const imgRef = ref(null)
const containerRef = ref(null)
const pos = ref({ x: 0, y: 0 })
const scale = ref(1)
const rotating = ref(0)
let dragging = false
let last = { x: 0, y: 0 }

onMounted(() => {
  // initialize scale to fit image into viewport once loaded
  const img = imgRef.value
  img.onload = () => {
    const sw = props.outputWidth
    const sh = props.outputHeight
    if (props.initialTransform) {
      // rehydrate previous transform
      scale.value = props.initialTransform.scale || 1
      rotating.value = props.initialTransform.rotate || 0
      pos.value = { x: props.initialTransform.x || 0, y: props.initialTransform.y || 0 }
      // if transform was created with different output size, scale positions accordingly
      if (props.initialTransform.outputWidth && props.initialTransform.outputWidth !== sw) {
        const sx = sw / props.initialTransform.outputWidth
        const sy = sh / props.initialTransform.outputHeight
        pos.value.x = pos.value.x * sx
        pos.value.y = pos.value.y * sy
        scale.value = scale.value * ((sx + sy) / 2)
      }
    } else {
      const r = Math.max(sw / img.naturalWidth, sh / img.naturalHeight)
      scale.value = r
      pos.value = { x: (sw - img.naturalWidth * scale.value) / 2, y: (sh - img.naturalHeight * scale.value) / 2 }
    }
  }
})

function onPointerDown(e) {
  dragging = true
  last = { x: e.clientX, y: e.clientY }
  window.addEventListener('pointermove', onPointerMove)
  window.addEventListener('pointerup', onPointerUp)
}
function onPointerMove(e) {
  if (!dragging) return
  const dx = e.clientX - last.x
  const dy = e.clientY - last.y
  pos.value.x += dx
  pos.value.y += dy
  last = { x: e.clientX, y: e.clientY }
}
function onPointerUp() {
  dragging = false
  window.removeEventListener('pointermove', onPointerMove)
  window.removeEventListener('pointerup', onPointerUp)
}

function onWheel(e) {
  e.preventDefault()
  const delta = -e.deltaY
  const factor = delta > 0 ? 1.08 : 0.92
  // zoom around mouse position
  const rect = containerRef.value.getBoundingClientRect()
  const mx = e.clientX - rect.left
  const my = e.clientY - rect.top
  const prevScale = scale.value
  scale.value = Math.max(0.2, Math.min(6, scale.value * factor))
  // adjust pos so point under cursor remains
  pos.value.x = mx - ((mx - pos.value.x) * (scale.value / prevScale))
  pos.value.y = my - ((my - pos.value.y) * (scale.value / prevScale))
}

function presetFit() {
  const img = imgRef.value
  const sw = props.outputWidth
  const sh = props.outputHeight
  const r = Math.min(sw / img.naturalWidth, sh / img.naturalHeight)
  scale.value = r
  pos.value = { x: (sw - img.naturalWidth * r) / 2, y: (sh - img.naturalHeight * r) / 2 }
}
function presetFill() {
  const img = imgRef.value
  const sw = props.outputWidth
  const sh = props.outputHeight
  const r = Math.max(sw / img.naturalWidth, sh / img.naturalHeight)
  scale.value = r
  pos.value = { x: (sw - img.naturalWidth * r) / 2, y: (sh - img.naturalHeight * r) / 2 }
}

async function apply() {
  const img = imgRef.value
  const canvas = document.createElement('canvas')
  canvas.width = props.outputWidth
  canvas.height = props.outputHeight
  const ctx = canvas.getContext('2d')
  ctx.save()
  ctx.translate(pos.value.x, pos.value.y)
  ctx.rotate((rotating.value * Math.PI) / 180)
  ctx.scale(scale.value, scale.value)
  ctx.drawImage(img, 0, 0)
  ctx.restore()
  const dataUrl = canvas.toDataURL('image/png')

  const transform = {
    x: pos.value.x,
    y: pos.value.y,
    scale: scale.value,
    rotate: rotating.value,
    outputWidth: props.outputWidth,
    outputHeight: props.outputHeight,
    naturalWidth: img.naturalWidth,
    naturalHeight: img.naturalHeight,
  }

  emit('apply', { dataUrl, transform })
}
</script>

<template>
  <div class="editor-overlay">
    <div class="editor">
      <div class="viewport" :style="{ width: `${outputWidth}px`, height: `${outputHeight}px` }" ref="containerRef" @pointerdown="onPointerDown" @wheel.prevent="onWheel">
        <img :src="src" ref="imgRef" class="editable" :style="{ transform: `translate(${pos.x}px, ${pos.y}px) scale(${scale}) rotate(${rotating}deg)` }" />
      </div>

      <div class="controls">
        <div class="presets">
          <button @click="presetFit">Fit</button>
          <button @click="presetFill">Fill</button>
          <label>Rotate <input type="range" min="-180" max="180" v-model.number="rotating" /></label>
        </div>
        <div class="actions">
          <button class="ghost" @click="$emit('cancel')">Cancel</button>
          <button class="primary" @click="apply">Apply</button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.editor-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.5);
  z-index: 60;
}
.editor {
  background: #fff;
  padding: 18px;
  border-radius: 12px;
  box-shadow: 0 20px 50px rgba(0,0,0,0.4);
  display: grid;
  gap: 12px;
}
.viewport {
  position: relative;
  overflow: hidden;
  background: #f3f3f3;
}
.editable {
  position: absolute;
  left: 0;
  top: 0;
  user-select: none;
  touch-action: none;
}
.controls {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}
.presets button { margin-right: 8px }
.primary { background: #c85a7c; color: #fff; padding: 8px 14px; border: none; border-radius: 8px }
.ghost { background: transparent; border: 1px solid #ddd; padding: 8px 14px; border-radius: 8px }
</style>
