<template>
  <div class="sticker-canvas" ref="containerRef">
    <v-stage
      ref="stageRef"
      :config="stageConfig"
      @click="onStageClick"
      @tap="onStageClick"
    >
      <v-layer>
        <v-image :config="imageConfig" />
      </v-layer>
      <v-layer ref="stickerLayerRef">
        <v-text
          v-for="s in stickers"
          :key="s.id"
          :config="stickerConfig(s)"
          @click="selectSticker(s.id, $event)"
          @tap="selectSticker(s.id, $event)"
          @dragend="onDragEnd(s.id, $event)"
          @transformend="onTransformEnd(s.id, $event)"
        />
        <v-transformer ref="transformerRef" :config="transformerConfig" />
      </v-layer>
    </v-stage>

    <!-- Delete selected sticker button -->
    <button
      v-if="selectedId"
      class="sticker-canvas__delete"
      type="button"
      aria-label="Remove sticker"
      @click="removeSelected"
    >
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
        <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
      </svg>
    </button>

    <!-- Add sticker / Next -->
    <div class="sticker-canvas__bar">
      <button class="sticker-canvas__add-btn" type="button" @click="trayOpen = true">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
          <circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/>
        </svg>
        Add sticker
      </button>
      <BaseButton variant="primary" class="sticker-canvas__next-btn" @click="done">Next</BaseButton>
    </div>

    <!-- Sticker tray -->
    <StickerTray v-model="trayOpen" @pick="addStickerFromTray" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
import Konva from 'konva'
import BaseButton from '@/components/BaseButton.vue'
import StickerTray from '@/components/StickerTray.vue'
import type { StickerLayer } from '@/types'

const props = defineProps<{
  croppedUrl: string
  orientation: 'landscape' | 'portrait'
  stickers: StickerLayer[]
}>()

const emit = defineEmits<{
  (e: 'add-sticker', s: StickerLayer): void
  (e: 'update-sticker', id: string, patch: Partial<StickerLayer>): void
  (e: 'remove-sticker', id: string): void
  (e: 'done', blob: Blob): void
}>()

const containerRef   = ref<HTMLDivElement>()
const stageRef       = ref()
const transformerRef = ref()
const stickerLayerRef = ref()

const trayOpen   = ref(false)
const selectedId = ref<string | null>(null)

// Stage dimensions fitted to container
const stageW = ref(375)
const stageH = ref(225)

const ASPECT = props.orientation === 'landscape' ? (1600 / 960) : (960 / 1600)

function sizeStage() {
  if (!containerRef.value) return
  const { width, height } = containerRef.value.getBoundingClientRect()
  const availH = height - 72  // bottom bar
  if (width / availH > ASPECT) {
    stageH.value = availH
    stageW.value = availH * ASPECT
  } else {
    stageW.value = width
    stageH.value = width / ASPECT
  }
  loadImage()
}

const ro = new ResizeObserver(sizeStage)
onMounted(() => {
  if (containerRef.value) ro.observe(containerRef.value)
  sizeStage()
  attachPinchListeners()
})
onBeforeUnmount(() => {
  ro.disconnect()
  detachPinchListeners()
})

// ── Image ─────────────────────────────────────────────────────────────────────

const bgImage = ref<HTMLImageElement | null>(null)
function loadImage() {
  const i = new Image()
  i.onload = () => { bgImage.value = i }
  i.src = props.croppedUrl
}
watch(() => props.croppedUrl, () => loadImage(), { immediate: true })

const stageConfig = computed(() => ({ width: stageW.value, height: stageH.value }))
const imageConfig = computed(() => ({
  image: bgImage.value,
  x: 0, y: 0,
  width:  stageW.value,
  height: stageH.value,
}))

const transformerConfig = {
  enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
  rotateEnabled: true,
  borderStroke: 'rgba(255,255,255,0.8)',
  anchorFill: '#fff',
  anchorSize: 18,   // larger for touch
  keepRatio: true,
  boundBoxFunc: (_: any, newBox: any) => newBox,
}

// ── Stickers ──────────────────────────────────────────────────────────────────

const EMOJI_FONT_SIZE = 52

function stickerConfig(s: StickerLayer) {
  return {
    id: s.id,
    text: stickerEmoji(s.type),
    fontSize: EMOJI_FONT_SIZE,
    fontFamily: '"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif',
    x: s.x,
    y: s.y,
    scaleX: s.scale,
    scaleY: s.scale,
    rotation: s.rotation,
    draggable: true,
    offsetX: EMOJI_FONT_SIZE / 2,
    offsetY: EMOJI_FONT_SIZE / 2,
  }
}

import { STICKERS } from '@/assets/stickers/index'
function stickerEmoji(type: string): string {
  return STICKERS.find(s => s.id === type)?.emoji ?? '⭐'
}

function selectSticker(id: string, e: any) {
  e.cancelBubble = true
  selectedId.value = id
  nextTick(() => {
    const layer = stickerLayerRef.value?.getNode()
    const node  = layer?.findOne(`#${id}`)
    const tr    = transformerRef.value?.getNode()
    if (node && tr) tr.nodes([node])
  })
}

function onStageClick(e: any) {
  if (e.target === e.target.getStage()) {
    selectedId.value = null
    transformerRef.value?.getNode()?.nodes([])
  }
}

function removeSelected() {
  if (!selectedId.value) return
  emit('remove-sticker', selectedId.value)
  selectedId.value = null
  transformerRef.value?.getNode()?.nodes([])
}

function onDragEnd(id: string, e: any) {
  emit('update-sticker', id, { x: e.target.x(), y: e.target.y() })
}

function onTransformEnd(id: string, e: any) {
  emit('update-sticker', id, {
    x:        e.target.x(),
    y:        e.target.y(),
    scale:    e.target.scaleX(),
    rotation: e.target.rotation(),
  })
}

function addStickerFromTray(stickerId: string) {
  const s: StickerLayer = {
    id:       `${stickerId}-${Date.now()}`,
    type:     stickerId,
    x:        stageW.value / 2,
    y:        stageH.value / 2,
    scale:    1,
    rotation: 0,
  }
  emit('add-sticker', s)
  trayOpen.value = false
  // Auto-select the new sticker
  nextTick(() => selectSticker(s.id, { cancelBubble: false }))
}

// ── Pinch-to-resize ───────────────────────────────────────────────────────────

let pinchStartDist  = 0
let pinchStartScale = 1

function touchDist(touches: TouchList) {
  const dx = touches[0].clientX - touches[1].clientX
  const dy = touches[0].clientY - touches[1].clientY
  return Math.hypot(dx, dy)
}

function onPinchStart(e: TouchEvent) {
  if (e.touches.length !== 2 || !selectedId.value) return
  pinchStartDist = touchDist(e.touches)
  const s = props.stickers.find(x => x.id === selectedId.value)
  pinchStartScale = s?.scale ?? 1
}

function onPinchMove(e: TouchEvent) {
  if (e.touches.length !== 2 || !selectedId.value || pinchStartDist === 0) return
  e.preventDefault()
  const newScale = Math.max(0.2, Math.min(6, pinchStartScale * (touchDist(e.touches) / pinchStartDist)))
  emit('update-sticker', selectedId.value, { scale: newScale })
}

function onPinchEnd() {
  pinchStartDist  = 0
  pinchStartScale = 1
}

function attachPinchListeners() {
  const el = containerRef.value
  if (!el) return
  el.addEventListener('touchstart', onPinchStart, { passive: true })
  el.addEventListener('touchmove',  onPinchMove,  { passive: false })
  el.addEventListener('touchend',   onPinchEnd,   { passive: true })
}

function detachPinchListeners() {
  const el = containerRef.value
  if (!el) return
  el.removeEventListener('touchstart', onPinchStart)
  el.removeEventListener('touchmove',  onPinchMove)
  el.removeEventListener('touchend',   onPinchEnd)
}

// ── Output ────────────────────────────────────────────────────────────────────

async function done() {
  // Deselect to hide transformer handles before capture
  selectedId.value = null
  transformerRef.value?.getNode()?.nodes([])
  await nextTick()

  const stage: Konva.Stage = stageRef.value?.getNode()
  if (!stage) return

  const outputW = props.orientation === 'landscape' ? 1600 : 960
  const pixelRatio = outputW / stageW.value

  // Use explicit mimeType so the blob is a real JPEG, not the default PNG
  const blob = await stage.toBlob({ pixelRatio, mimeType: 'image/jpeg', quality: 0.92 }) as Blob | null
  if (blob) emit('done', blob)
}
</script>

<style scoped lang="scss">
.sticker-canvas {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: #111;
  overflow: hidden;

  :deep(.konvajs-content) {
    flex-shrink: 0;
  }

  &__delete {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(200, 30, 30, 0.85);
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    z-index: 10;
  }

  &__bar {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 72px;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-4);
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
  }

  &__add-btn {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    border: 1.5px solid var(--color-border);
    background: transparent;
    color: var(--color-text);
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
  }

  &__next-btn {
    margin-left: auto;
    min-width: 96px;
  }
}
</style>
