<script setup lang="ts">
import * as XLSX from 'xlsx'
import type { TableColumn } from '@nuxt/ui'
import type { PurchaseInsert, EquipmentCategory } from '~/types/purchase'

const props = defineProps<{
  open: boolean
}>()

const emit = defineEmits<{
  'update:open': [value: boolean]
  done: []
}>()

// 카테고리 한국어 → 영문 매핑 (별칭 포함)
const CATEGORY_MAP: Record<string, EquipmentCategory> = {
  '텐트': 'tent',
  '침낭/매트': 'sleeping',
  '침낭': 'sleeping',
  '취사도구': 'cooking',
  '조리': 'cooking',
  '조명': 'lighting',
  '의류': 'clothing',
  '배낭': 'backpack',
  '가구': 'furniture',
  '가구/의자': 'furniture',
  '안전장비': 'safety',
  '전자기기': 'electronics',
  '기타': 'other'
}

// 허용 카테고리 문자열 목록 (오류 메시지용)
const VALID_CATEGORIES = Object.keys(CATEGORY_MAP).join(', ')

type RowStatus = 'valid' | 'error'
interface PreviewRow {
  _index: number
  data: PurchaseInsert
  status: RowStatus
  errors: string[]
}

const { bulkCreatePurchases } = usePurchases()

const file = ref<File | null>(null)
const rows = ref<PreviewRow[]>([])
const step = ref<'upload' | 'preview'>('upload')
const importing = ref(false)
const isDragging = ref(false)

const validRows = computed(() => rows.value.filter(r => r.status === 'valid'))
const errorRows = computed(() => rows.value.filter(r => r.status === 'error'))

// 모달 닫힐 때 상태 초기화
watch(() => props.open, (val) => {
  if (!val) resetState()
})

function resetState() {
  file.value = null
  rows.value = []
  step.value = 'upload'
  importing.value = false
}

// Excel 날짜 숫자 → ISO 문자열 변환
function excelDateToISO(value: unknown): string | null {
  if (value instanceof Date) {
    return value.toISOString().split('T')[0] ?? null
  }
  if (typeof value === 'number') {
    const date = XLSX.SSF.parse_date_code(value)
    if (!date) return null
    const m = String(date.m).padStart(2, '0')
    const d = String(date.d).padStart(2, '0')
    return `${date.y}-${m}-${d}`
  }
  if (typeof value === 'string' && value.trim()) {
    // YYYY-MM-DD 또는 YYYY/MM/DD 형식 지원
    const normalized = value.trim().replace(/\//g, '-')
    if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) return normalized
  }
  return null
}

// 엑셀 파일 파싱 및 검증
function parseExcel(f: File) {
  const reader = new FileReader()
  reader.onload = (e) => {
    const data = e.target?.result
    if (!data) return

    const wb = XLSX.read(data, { type: 'array', cellDates: true })
    const ws = wb.Sheets[wb.SheetNames[0] ?? '']
    if (!ws) {
      rows.value = []
      step.value = 'preview'
      return
    }

    const raw = XLSX.utils.sheet_to_json<Record<string, unknown>>(ws, { defval: '' })

    rows.value = raw.map((row, idx): PreviewRow => {
      const errors: string[] = []

      // 필수 필드 검증
      const name = String(row['장비명'] ?? '').trim()
      if (!name) errors.push('장비명 필수')

      const categoryRaw = String(row['카테고리'] ?? '').trim()
      const category = CATEGORY_MAP[categoryRaw]
      if (!categoryRaw) {
        errors.push('카테고리 필수')
      } else if (!category) {
        errors.push(`카테고리 오류: "${categoryRaw}" (허용값: ${VALID_CATEGORIES})`)
      }

      const priceRaw = row['가격']
      const price = typeof priceRaw === 'number' ? priceRaw : Number(String(priceRaw ?? '').replace(/,/g, ''))
      if (!priceRaw && priceRaw !== 0) {
        errors.push('가격 필수')
      } else if (isNaN(price) || price < 0) {
        errors.push('가격은 0 이상의 숫자여야 합니다')
      }

      const purchaseDateISO = excelDateToISO(row['구매일'])
      if (!purchaseDateISO) errors.push('구매일 필수 (YYYY-MM-DD 형식)')

      // 선택 필드
      const warrantyISO = row['보증만료일'] ? excelDateToISO(row['보증만료일']) : undefined

      const purchaseData: PurchaseInsert = {
        name,
        category: (category ?? 'other') as EquipmentCategory,
        brand: String(row['브랜드'] ?? '').trim() || undefined,
        price: isNaN(price) ? 0 : price,
        purchase_date: purchaseDateISO ?? '',
        store: String(row['구매처'] ?? '').trim() || undefined,
        warranty_until: warrantyISO ?? undefined,
        notes: String(row['메모'] ?? '').trim() || undefined
      }

      return {
        _index: idx + 1,
        data: purchaseData,
        status: errors.length === 0 ? 'valid' : 'error',
        errors
      }
    })

    step.value = 'preview'
  }
  reader.readAsArrayBuffer(f)
}

// 파일 선택 처리
function handleFileChange(e: Event) {
  const target = e.target as HTMLInputElement
  const selected = target.files?.[0]
  if (!selected) return
  file.value = selected
  parseExcel(selected)
}

// 드래그 앤 드롭 처리
function handleDrop(e: DragEvent) {
  isDragging.value = false
  const dropped = e.dataTransfer?.files?.[0]
  if (!dropped) return
  if (!dropped.name.match(/\.(xlsx|xls)$/i)) return
  file.value = dropped
  parseExcel(dropped)
}

// 템플릿 다운로드
function downloadTemplate() {
  const headers = ['장비명', '카테고리', '브랜드', '가격', '구매일', '구매처', '보증만료일', '메모']
  const sample = ['코베아 타프', '텐트', '코베아', 120000, '2026-01-15', '캠핑아웃도어', '2027-01-15', '']
  const ws = XLSX.utils.aoa_to_sheet([headers, sample])

  // 컬럼 너비 설정
  ws['!cols'] = headers.map(() => ({ wch: 16 }))

  const wb = XLSX.utils.book_new()
  XLSX.utils.book_append_sheet(wb, ws, '구매내역')
  XLSX.writeFile(wb, '구매내역_템플릿.xlsx')
}

// 저장 처리
async function handleConfirm() {
  if (validRows.value.length === 0) return
  importing.value = true
  const count = await bulkCreatePurchases(validRows.value.map(r => r.data))
  importing.value = false
  if (count > 0) {
    emit('update:open', false)
    emit('done')
  }
}

// 뒤로가기
function handleBack() {
  step.value = 'upload'
  rows.value = []
  file.value = null
}

// 테이블 컬럼 정의
const previewColumns: TableColumn<PreviewRow>[] = [
  { id: 'row', header: '행' },
  { id: 'status', header: '상태' },
  { id: 'name', header: '장비명' },
  { id: 'category', header: '카테고리' },
  { id: 'price', header: '가격' },
  { id: 'purchase_date', header: '구매일' },
  { id: 'errors', header: '오류' }
]

function formatPrice(price: number) {
  return price.toLocaleString('ko-KR') + '원'
}
</script>

<template>
  <UModal
    :open="props.open"
    title="엑셀 대량 업로드"
    :ui="{ content: 'max-w-4xl' }"
    @update:open="emit('update:open', $event)"
  >
    <template #body>
      <!-- 업로드 단계 -->
      <div v-if="step === 'upload'" class="space-y-4">
        <!-- 파일 드롭존 -->
        <div
          class="border-2 border-dashed rounded-lg p-10 text-center cursor-pointer transition-colors"
          :class="isDragging
            ? 'border-primary-500 bg-primary-50 dark:bg-primary-950'
            : 'border-gray-300 dark:border-gray-600 hover:border-primary-400'"
          @click="($refs.fileInput as HTMLInputElement).click()"
          @dragover.prevent="isDragging = true"
          @dragleave="isDragging = false"
          @drop.prevent="handleDrop"
        >
          <UIcon name="i-lucide-file-spreadsheet" class="text-5xl text-gray-400 dark:text-gray-500 mb-3 mx-auto" />
          <p class="text-base font-medium text-gray-700 dark:text-gray-300">
            {{ file ? file.name : '파일을 클릭하거나 드래그하여 업로드' }}
          </p>
          <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">.xlsx, .xls 파일 지원</p>
          <input
            ref="fileInput"
            type="file"
            accept=".xlsx,.xls"
            class="hidden"
            @change="handleFileChange"
          />
        </div>

        <!-- 템플릿 다운로드 -->
        <div class="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
          <UIcon name="i-lucide-info" class="shrink-0" />
          <span>처음 사용하시나요?</span>
          <UButton
            variant="link"
            size="sm"
            icon="i-lucide-download"
            label="템플릿 다운로드"
            class="p-0"
            @click.stop="downloadTemplate"
          />
        </div>

        <!-- 컬럼 안내 -->
        <UAlert
          color="neutral"
          variant="soft"
          title="엑셀 파일 형식 안내"
          :description="`필수 컬럼: 장비명, 카테고리, 가격, 구매일 / 카테고리 허용값: 텐트, 침낭/매트, 취사도구, 조명, 의류, 배낭, 가구, 안전장비, 전자기기, 기타`"
        />
      </div>

      <!-- 미리보기 단계 -->
      <div v-else class="space-y-4">
        <!-- 요약 뱃지 -->
        <div class="flex items-center gap-3 flex-wrap">
          <UBadge color="neutral" variant="soft" size="lg">
            총 {{ rows.length }}행
          </UBadge>
          <UBadge color="success" variant="soft" size="lg">
            유효 {{ validRows.length }}행
          </UBadge>
          <UBadge v-if="errorRows.length > 0" color="error" variant="soft" size="lg">
            오류 {{ errorRows.length }}행
          </UBadge>
        </div>

        <!-- 미리보기 테이블 -->
        <div class="max-h-96 overflow-auto rounded-lg border border-gray-200 dark:border-gray-700">
          <UTable :data="rows" :columns="previewColumns">
            <template #row-cell="{ row }">
              <span class="text-gray-500 text-xs">{{ row.original._index }}</span>
            </template>
            <template #status-cell="{ row }">
              <UBadge
                :color="row.original.status === 'valid' ? 'success' : 'error'"
                variant="soft"
                size="xs"
              >
                {{ row.original.status === 'valid' ? '유효' : '오류' }}
              </UBadge>
            </template>
            <template #name-cell="{ row }">
              <span class="font-medium">{{ row.original.data.name }}</span>
            </template>
            <template #category-cell="{ row }">
              {{ row.original.data.category }}
            </template>
            <template #price-cell="{ row }">
              {{ formatPrice(row.original.data.price) }}
            </template>
            <template #purchase_date-cell="{ row }">
              {{ row.original.data.purchase_date }}
            </template>
            <template #errors-cell="{ row }">
              <div v-if="row.original.errors.length > 0" class="space-y-1">
                <UBadge
                  v-for="(err, i) in row.original.errors"
                  :key="i"
                  color="error"
                  variant="soft"
                  size="xs"
                  class="block text-left"
                >
                  {{ err }}
                </UBadge>
              </div>
            </template>
          </UTable>
        </div>

        <!-- 오류 안내 -->
        <UAlert
          v-if="errorRows.length > 0"
          color="warning"
          variant="soft"
          icon="i-lucide-triangle-alert"
          :title="`${errorRows.length}개 행에 오류가 있습니다`"
          description="오류 행은 저장에서 제외됩니다. 엑셀 파일을 수정 후 다시 업로드하거나, 유효한 행만 저장할 수 있습니다."
        />
      </div>
    </template>

    <template #footer>
      <!-- 업로드 단계 푸터 -->
      <div v-if="step === 'upload'" class="flex justify-end">
        <UButton color="neutral" variant="ghost" label="취소" @click="emit('update:open', false)" />
      </div>

      <!-- 미리보기 단계 푸터 -->
      <div v-else class="flex items-center justify-between w-full">
        <UButton
          color="neutral"
          variant="ghost"
          icon="i-lucide-arrow-left"
          label="뒤로"
          @click="handleBack"
        />
        <div class="flex gap-2">
          <UButton color="neutral" variant="ghost" label="취소" @click="emit('update:open', false)" />
          <UButton
            :disabled="validRows.length === 0 || importing"
            :loading="importing"
            icon="i-lucide-save"
            :label="`유효한 ${validRows.length}행 저장`"
            @click="handleConfirm"
          />
        </div>
      </div>
    </template>
  </UModal>
</template>
