<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { NAlert, NButton, NCard, NProgress, NResult, NTag } from 'naive-ui'
import { useRouter } from 'vue-router'
import { useCloudsStore } from '@/stores/clouds'
import { useAuthStore } from '@/stores/auth'
import { downloadCloudBadgeCard } from '@/lib/cloudBadges'
import { useUpload } from '@/composables/useUpload'
import MapPickerModal from '@/components/cloud/MapPickerModal.vue'

const router = useRouter()
const authStore = useAuthStore()
const cloudsStore = useCloudsStore()
const { items, uploading, overallProgress, currentItemIndex, totalItems, addFiles, removeItem, clearAll, validateAll, uploadAll } = useUpload()

const activeId = ref<string | null>(null)
const dragOver = ref(false)
const successMsg = ref(false)
const unlockedBadges = ref<Awaited<ReturnType<typeof uploadAll>>['unlockedBadges']>([])
const errorMsg = ref('')
const fileInput = ref<HTMLInputElement | null>(null)
const mapPickerOpen = ref(false)

const activeItem = computed(() => {
  if (!activeId.value) return null
  return items.value.find(i => i.id === activeId.value) ?? null
})

watch(() => items.value.length, () => {
  if (items.value.length > 0 && !activeId.value) {
    activeId.value = items.value[0].id
  }
  if (items.value.length === 0) {
    activeId.value = null
  }
})

function selectItem(id: string) {
  activeId.value = id
}

function handleDrop(e: DragEvent) {
  dragOver.value = false
  if (e.dataTransfer?.files) {
    addFiles(Array.from(e.dataTransfer.files))
  }
}

function handleFileSelect(e: Event) {
  const target = e.target as HTMLInputElement
  if (target.files && target.files.length > 0) {
    addFiles(Array.from(target.files))
  }
  target.value = ''
}

function handleRemove(id: string) {
  removeItem(id)
  if (activeId.value === id) {
    activeId.value = items.value[0]?.id ?? null
  }
}

function updateActiveCoordinates(latitude: number | null, longitude: number | null) {
  if (!activeItem.value) return

  activeItem.value.latitude = latitude
  activeItem.value.longitude = longitude

  if (activeItem.value.errors.latitude) delete activeItem.value.errors.latitude
  if (activeItem.value.errors.longitude) delete activeItem.value.errors.longitude
}

async function openMapPicker() {
  if (!activeItem.value) return

  mapPickerOpen.value = true
}

function closeMapPicker() {
  mapPickerOpen.value = false
}

function confirmMapPicker(payload: { latitude: number; longitude: number }) {
  updateActiveCoordinates(payload.latitude, payload.longitude)
  closeMapPicker()
}

function clearCoordinates() {
  updateActiveCoordinates(null, null)
}

function updateActivePublicState(isPublic: boolean) {
  if (!activeItem.value) return
  activeItem.value.isHidden = !isPublic
}

async function handleSubmit() {
  errorMsg.value = ''
  const allValid = validateAll()
  if (!allValid) {
    const firstInvalid = items.value.find(i => Object.keys(i.errors).length > 0)
    if (firstInvalid) {
      activeId.value = firstInvalid.id
      await nextTick()
      const el = document.getElementById(`field-${firstInvalid.id}-cloudCategory`)
      el?.scrollIntoView({ behavior: 'smooth', block: 'center' })
    }
    return
  }

  const result = await uploadAll()
  if (result.ok) {
    unlockedBadges.value = result.unlockedBadges
    successMsg.value = true
  } else {
    errorMsg.value = '上传失败，请稍后重试'
  }
}

function resetAfterSuccess() {
  successMsg.value = false
  unlockedBadges.value = []
  errorMsg.value = ''
}

async function saveBadge(badge: NonNullable<typeof unlockedBadges.value[number]>) {
  await downloadCloudBadgeCard({
    cloudName: badge.cloudName,
    cloudNameEn: badge.cloudNameEn,
    unlockedAt: badge.unlockedAt,
    username: authStore.profile?.username || authStore.user?.email || 'OpenCloud 用户',
    rarity: badge.rarity,
  })
}

function rarityLabel(rarity: NonNullable<typeof unlockedBadges.value[number]>['rarity']) {
  if (rarity === 'common') return '常见'
  if (rarity === 'uncommon') return '少见'
  return '罕见'
}

function formatUnlockedAt(iso: string) {
  return new Date(iso).toLocaleDateString('zh-CN', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  })
}

function onLatInput(e: Event) {
  const val = parseFloat((e.target as HTMLInputElement).value)
  if (activeItem.value) {
    activeItem.value.latitude = isNaN(val) ? null : val
    if (activeItem.value.errors.latitude) delete activeItem.value.errors.latitude
    if (activeItem.value.errors.longitude) delete activeItem.value.errors.longitude
  }
}

function onLngInput(e: Event) {
  const val = parseFloat((e.target as HTMLInputElement).value)
  if (activeItem.value) {
    activeItem.value.longitude = isNaN(val) ? null : val
    if (activeItem.value.errors.latitude) delete activeItem.value.errors.latitude
    if (activeItem.value.errors.longitude) delete activeItem.value.errors.longitude
  }
}

function formatDatetimeLocal(iso: string): string {
  const d = new Date(iso)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}

function onCapturedAtChange(e: Event) {
  const val = (e.target as HTMLInputElement).value
  if (activeItem.value && val) {
    activeItem.value.capturedAt = new Date(val).toISOString()
    if (activeItem.value.errors.capturedAt) {
      delete activeItem.value.errors.capturedAt
    }
  }
}

function onCategoryChange(e: Event) {
  const val = (e.target as HTMLSelectElement).value
  if (!activeItem.value) return
  if (val === 'other') {
    activeItem.value.cloudCategoryId = 'other'
  } else if (val === '') {
    activeItem.value.cloudCategoryId = null
  } else {
    activeItem.value.cloudCategoryId = Number(val)
  }
  activeItem.value.errors = {}
}

onMounted(() => { cloudsStore.fetchCloudTypes() })
onUnmounted(() => {
  for (const item of items.value) URL.revokeObjectURL(item.preview)
})
</script>

<template>
  <div>
    <section class="border-b border-sky-100 bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]">
      <div class="max-w-6xl mx-auto px-4 py-10">
        <p class="text-sm font-medium uppercase tracking-[0.24em] text-sky-700">Cloud Upload</p>
        <h1 class="mt-3 text-4xl font-bold text-slate-900">上传云图</h1>
        <p class="mt-4 max-w-2xl text-sm leading-7 text-slate-600">
          批量整理你的云图记录。类别和拍摄时间必填，经纬度既可以手动输入，也可以在迷你地图里点选回填。
        </p>
      </div>
    </section>

    <div class="max-w-6xl mx-auto px-4 py-8">
      <input ref="fileInput" type="file" accept="image/*" multiple class="hidden" @change="handleFileSelect" />

    <div v-if="successMsg" class="flex items-center justify-center min-h-[60vh]">
      <div class="w-full max-w-5xl">
        <NResult status="success" title="已提交审核" class="border border-slate-200 bg-white shadow-sm">
          <template #default>
            <p class="text-slate-500">
              <template v-if="unlockedBadges.length">
                新点亮了 {{ unlockedBadges.length }} 枚图鉴徽章。图片审核通过后会出现在画廊和地图中。
              </template>
              <template v-else>
                这批云图已进入待审核队列，审核通过后会出现在画廊和地图中。
              </template>
            </p>
          </template>
        </NResult>

        <div v-if="unlockedBadges.length" class="mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3">
          <NCard
            v-for="badge in unlockedBadges"
            :key="badge.cloudTypeId"
            class="border border-amber-200 bg-[linear-gradient(180deg,#fffbeb_0%,#ffffff_100%)] shadow-sm"
          >
            <div class="flex h-16 w-16 items-center justify-center border border-amber-300 bg-amber-400 text-3xl text-white shadow-sm">
              {{ badge.cloudName.slice(0, 1) }}
            </div>
            <div class="mt-5">
              <div class="flex items-center gap-3">
                <h3 class="text-2xl font-bold text-gray-900">{{ badge.cloudName }}</h3>
                <NTag :bordered="false" type="warning">
                  {{ rarityLabel(badge.rarity) }}
                </NTag>
              </div>
              <p class="mt-1 text-sm text-gray-500">{{ badge.cloudNameEn }}</p>
              <p class="mt-4 text-sm text-gray-600">解锁时间：{{ formatUnlockedAt(badge.unlockedAt) }}</p>
            </div>

            <div class="mt-6 flex gap-3">
              <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky flex-1" @click="saveBadge(badge)">保存分享卡片</NButton>
              <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral flex-1" @click="router.push(`/encyclopedia/${badge.cloudTypeId}`)">查看详情</NButton>
            </div>
          </NCard>
        </div>

        <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
          <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="resetAfterSuccess">继续上传</NButton>
          <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--sky" @click="router.push('/encyclopedia')">前往图鉴</NButton>
          <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="router.push('/profile')">返回个人主页</NButton>
        </div>
      </div>
    </div>

    <template v-else>
      <div v-if="uploading" class="mb-6 border border-slate-200 bg-white p-5 shadow-sm">
        <div class="flex items-center justify-between mb-2">
          <span class="text-sm font-medium text-gray-700">正在上传 {{ currentItemIndex }} / {{ totalItems }}...</span>
          <span class="text-sm font-medium text-sky-600">{{ overallProgress }}%</span>
        </div>
        <NProgress
          type="line"
          :show-indicator="false"
          :percentage="overallProgress"
          color="#0ea5e9"
          rail-color="#dbe4ee"
          :height="10"
        />
      </div>

      <div
        v-if="items.length === 0"
        @dragover.prevent="dragOver = true"
        @dragleave.prevent="dragOver = false"
        @drop.prevent="handleDrop"
        @click="fileInput?.click()"
        class="flex flex-col items-center justify-center border-2 border-dashed py-20 cursor-pointer transition-colors bg-white shadow-sm"
        :class="dragOver ? 'border-sky-400 bg-sky-50' : 'border-gray-300 hover:border-sky-400 hover:bg-gray-50'"
      >
        <span class="text-5xl mb-4">☁️</span>
        <p class="text-lg font-medium text-gray-700 mb-1">点击或拖拽图片到此处</p>
        <p class="text-sm text-gray-400">支持 JPG、PNG 格式，可一次选择多张</p>
      </div>

      <template v-else>
        <div class="flex gap-6">
          <div class="flex-shrink-0 w-[480px]">
            <div v-if="activeItem" class="bg-gray-900 overflow-hidden mb-3 border border-slate-900">
              <img :src="activeItem.preview" alt="预览" class="w-full h-[360px] object-contain" />
            </div>
            <div class="flex gap-2 overflow-x-auto pb-2">
              <div
                v-for="item in items"
                :key="item.id"
                @click="selectItem(item.id)"
                class="relative flex-shrink-0 w-16 h-16 overflow-hidden cursor-pointer border-2 transition-colors bg-white"
                :class="activeId === item.id ? 'border-sky-500' : 'border-transparent hover:border-gray-300'"
              >
                <img :src="item.preview" alt="" class="w-full h-full object-cover" />
                <div v-if="Object.keys(item.errors).length > 0" class="absolute top-0 right-0 w-2.5 h-2.5 bg-red-500"></div>
                <button
                  @click.stop="handleRemove(item.id)"
                  class="absolute -top-1 -right-1 flex h-5 w-5 items-center justify-center bg-red-500 text-xs text-white"
                  style="opacity:0.8"
                >✕</button>
              </div>
              <div
                @click="fileInput?.click()"
                class="flex-shrink-0 w-16 h-16 border-2 border-dashed border-gray-300 flex items-center justify-center cursor-pointer bg-white hover:border-sky-400 hover:bg-gray-50 transition-colors"
              >
                <span class="text-gray-400 text-xl">+</span>
              </div>
            </div>
          </div>

          <div class="flex-1 min-w-0" v-if="activeItem">
            <NCard class="border border-gray-200 shadow-sm">
              <div class="space-y-5">
                <div class="flex items-center justify-between">
                  <h2 class="text-lg font-semibold text-gray-900">图片信息</h2>
                  <span class="text-sm text-gray-400">{{ items.findIndex(i => i.id === activeId) + 1 }} / {{ items.length }}</span>
                </div>

                <!-- 类别 * -->
                <div :id="`field-${activeItem.id}-cloudCategory`">
                  <label class="block text-sm font-medium text-gray-700 mb-1">
                    类别 <span class="text-red-500">*</span>
                  </label>
                  <select
                    :value="activeItem.cloudCategoryId ?? ''"
                    @change="onCategoryChange"
                    class="w-full px-3 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors bg-white"
                  >
                    <option value="" disabled>请选择</option>
                    <option v-for="ct in cloudsStore.cloudTypes" :key="ct.id" :value="ct.id">
                      {{ ct.name }}（{{ ct.name_en }}）
                    </option>
                    <option value="other">其他</option>
                  </select>
                  <div v-if="activeItem.cloudCategoryId === 'other'" class="mt-2">
                    <input
                      v-model="activeItem.customCloudType"
                      type="text"
                      placeholder="输入云的类型"
                      @input="activeItem.errors = {}"
                      class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors"
                    />
                  </div>
                  <p v-if="activeItem.errors.cloudCategory" class="text-sm text-red-500 mt-1">{{ activeItem.errors.cloudCategory }}</p>
                </div>

                <!-- 拍摄时间 * -->
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">
                    拍摄时间 <span class="text-red-500">*</span>
                  </label>
                  <input
                    type="datetime-local"
                    :value="formatDatetimeLocal(activeItem.capturedAt)"
                    @change="onCapturedAtChange"
                    class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors"
                  />
                  <p v-if="activeItem.errors.capturedAt" class="text-sm text-red-500 mt-1">{{ activeItem.errors.capturedAt }}</p>
                </div>

                <!-- 经纬度 -->
                <div>
                  <div class="mb-1 flex items-center justify-between gap-3">
                    <label class="block text-sm font-medium text-gray-700">经纬度</label>
                    <button
                      v-if="activeItem.latitude !== null || activeItem.longitude !== null"
                      type="button"
                      @click="clearCoordinates"
                      class="text-xs font-medium text-gray-400 transition-colors hover:text-gray-600"
                    >
                      清空
                    </button>
                  </div>
                  <div class="grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto] gap-2">
                    <div>
                      <input
                        :value="activeItem.latitude !== null ? activeItem.latitude : ''"
                        @input="onLatInput"
                        type="number"
                        step="any"
                        placeholder="纬度（如 39.90）"
                        class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors"
                      />
                      <p v-if="activeItem.errors.latitude" class="text-sm text-red-500 mt-1">{{ activeItem.errors.latitude }}</p>
                    </div>
                    <div>
                      <input
                        :value="activeItem.longitude !== null ? activeItem.longitude : ''"
                        @input="onLngInput"
                        type="number"
                        step="any"
                        placeholder="经度（如 116.40）"
                        class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors"
                      />
                      <p v-if="activeItem.errors.longitude" class="text-sm text-red-500 mt-1">{{ activeItem.errors.longitude }}</p>
                    </div>
                    <div>
                      <button
                        type="button"
                        @click="openMapPicker"
                        title="地图选点"
                        aria-label="地图选点"
                        class="flex h-10 w-10 items-center justify-center rounded-lg border border-sky-200 bg-sky-50 text-sky-700 transition-colors hover:bg-sky-100"
                      >
                        <span class="text-lg leading-none">🗺️</span>
                      </button>
                    </div>
                  </div>
                  <p class="text-xs text-gray-400 mt-1">选填，可手动输入，或点击右侧小地图图标选择</p>
                </div>

                <!-- 位置名称 -->
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">位置名称</label>
                  <input
                    v-model="activeItem.locationName"
                    type="text"
                    placeholder="如：北京、成都"
                    class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors"
                  />
                </div>

                <!-- 图片描述 -->
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">图片描述</label>
                  <textarea
                    v-model="activeItem.description"
                    rows="3"
                    placeholder="描述一下这张图片..."
                    class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-colors resize-none"
                  ></textarea>
                </div>

                <!-- 公开状态 -->
                <div class="border border-slate-200 bg-slate-50 px-4 py-3">
                  <div class="flex items-center justify-between gap-4">
                    <div>
                      <p class="text-sm font-medium text-gray-800">公开展示</p>
                      <p class="mt-1 text-xs text-gray-500">关闭后不会出现在画廊、地图和公开主页中。</p>
                    </div>
                    <input
                      :checked="!activeItem.isHidden"
                      type="checkbox"
                      :id="'isPublic-' + activeItem.id"
                      class="h-5 w-5 border-gray-300 text-sky-500 focus:ring-sky-500"
                      @change="updateActivePublicState(($event.target as HTMLInputElement).checked)"
                    />
                  </div>
                </div>
              </div>
            </NCard>
          </div>
        </div>

        <div class="mt-6 flex items-center justify-between">
          <p class="text-sm text-gray-500">共 {{ items.length }} 张图片</p>
          <div class="flex gap-3">
            <NButton secondary strong type="default" class="oc-panel-button oc-panel-button--neutral" @click="clearAll()" :disabled="uploading">清空</NButton>
            <NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky" @click="handleSubmit" :disabled="uploading">
              {{ uploading ? '上传中...' : '提交上传' }}
            </NButton>
          </div>
        </div>

        <NAlert v-if="errorMsg" class="mt-3" type="error" :show-icon="false" :bordered="false" title="上传失败">
          {{ errorMsg }}
        </NAlert>
      </template>
    </template>
    </div>
  </div>

  <MapPickerModal
    :open="mapPickerOpen"
    :latitude="activeItem?.latitude ?? null"
    :longitude="activeItem?.longitude ?? null"
    description="点击地图即可回填当前图片的经纬度，也可以继续手动修改。"
    footer-text="建议点选大致拍摄位置，上传时会继续做模糊化处理。"
    @close="closeMapPicker"
    @confirm="confirmMapPicker"
  />
</template>
