<template>
  <div v-if="open" class="modal-overlay" @click.self="$emit('close')">
    <div class="modal-card image-crop-modal">
      <div class="modal-head">
        <h3>{{ t('sections.profileCropTitle') }}</h3>
        <button class="btn btn-outline btn-xs" @click="$emit('close')">×</button>
      </div>

      <p class="modal-text subtle">{{ t('sections.profileCropSubtitle') }}</p>

      <div class="crop-canvas-wrap">
        <canvas
          ref="canvasRef"
          class="crop-canvas"
          width="340"
          height="340"
          @pointerdown="onPointerDown"
          @pointermove="onPointerMove"
          @pointerup="onPointerUp"
          @pointercancel="onPointerUp"
        />
        <div class="crop-circle-guide" />
      </div>

      <div class="crop-controls">
        <label>{{ t('labels.zoom') }}</label>
        <input type="range" min="1" max="3" step="0.01" :value="zoom" @input="onZoomInput" />
      </div>

      <div class="modal-actions split">
        <button class="btn btn-outline" @click="resetPosition">{{ t('actions.resetPosition') }}</button>
        <button class="btn btn-secondary" @click="$emit('close')">{{ t('actions.cancel') }}</button>
        <button class="btn btn-primary" @click="confirmCrop">{{ t('actions.applyCrop') }}</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref, watch } from 'vue'

const props = defineProps({
  open: { type: Boolean, default: false },
  sourceImage: { type: String, default: '' },
  t: { type: Function, required: true },
})

const emit = defineEmits(['close', 'confirm'])

const canvasRef = ref(null)
const zoom = ref(1)
const image = new Image()
const state = reactive({
  loaded: false,
  width: 0,
  height: 0,
  offsetX: 0,
  offsetY: 0,
  dragging: false,
  pointerId: null,
  lastX: 0,
  lastY: 0,
})

const CANVAS_SIZE = 340
const EXPORT_SIZE = 520

watch(
  () => [props.open, props.sourceImage],
  async ([open, src]) => {
    if (!open || !src) return
    await loadImage(src)
    resetPosition()
    drawPreview()
  },
  { immediate: true },
)

watch(zoom, () => {
  clampOffsets()
  drawPreview()
})

onMounted(() => {
  drawPreview()
})

function loadImage(src) {
  return new Promise((resolve, reject) => {
    image.onload = () => {
      state.loaded = true
      state.width = image.naturalWidth || image.width
      state.height = image.naturalHeight || image.height
      resolve()
    }
    image.onerror = () => reject(new Error('failed to load image'))
    image.src = src
  })
}

function onZoomInput(event) {
  zoom.value = Number(event.target.value || 1)
}

function resetPosition() {
  zoom.value = 1
  state.offsetX = 0
  state.offsetY = 0
  drawPreview()
}

function getDrawMetrics(size) {
  const baseScale = Math.max(size / state.width, size / state.height)
  const scale = baseScale * zoom.value
  const width = state.width * scale
  const height = state.height * scale
  const left = (size-width)/2 + state.offsetX
  const top = (size-height)/2 + state.offsetY
  return { width, height, left, top }
}

function clampOffsets() {
  if (!state.loaded) return
  const { width, height } = getDrawMetrics(CANVAS_SIZE)
  const maxOffsetX = Math.max(0, (width - CANVAS_SIZE) / 2)
  const maxOffsetY = Math.max(0, (height - CANVAS_SIZE) / 2)
  if (state.offsetX > maxOffsetX) state.offsetX = maxOffsetX
  if (state.offsetX < -maxOffsetX) state.offsetX = -maxOffsetX
  if (state.offsetY > maxOffsetY) state.offsetY = maxOffsetY
  if (state.offsetY < -maxOffsetY) state.offsetY = -maxOffsetY
}

function drawPreview() {
  const canvas = canvasRef.value
  if (!canvas) return
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE)
  ctx.fillStyle = '#f0f2f8'
  ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE)

  if (!state.loaded) return
  const { width, height, left, top } = getDrawMetrics(CANVAS_SIZE)
  ctx.drawImage(image, left, top, width, height)
}

function onPointerDown(event) {
  if (!state.loaded) return
  state.dragging = true
  state.pointerId = event.pointerId
  state.lastX = event.clientX
  state.lastY = event.clientY
  event.target.setPointerCapture(event.pointerId)
}

function onPointerMove(event) {
  if (!state.dragging || state.pointerId !== event.pointerId) return
  const dx = event.clientX - state.lastX
  const dy = event.clientY - state.lastY
  state.lastX = event.clientX
  state.lastY = event.clientY
  state.offsetX += dx
  state.offsetY += dy
  clampOffsets()
  drawPreview()
}

function onPointerUp(event) {
  if (state.pointerId !== event.pointerId) return
  state.dragging = false
  state.pointerId = null
}

function confirmCrop() {
  if (!state.loaded) return
  const canvas = document.createElement('canvas')
  canvas.width = EXPORT_SIZE
  canvas.height = EXPORT_SIZE
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  const { width, height, left, top } = getDrawMetrics(EXPORT_SIZE)
  ctx.fillStyle = '#f0f2f8'
  ctx.fillRect(0, 0, EXPORT_SIZE, EXPORT_SIZE)
  ctx.drawImage(image, left, top, width, height)
  emit('confirm', canvas.toDataURL('image/jpeg', 0.9))
}
</script>

