<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import type { Factory, Order } from '@/shared/types'
import { api } from '@/utils/api'
import type { ImportPreviewRow } from '@/utils/orderImport'
import { buildImportPreview, readSpreadsheetRows } from '@/utils/orderImport'

const props = defineProps<{ open: boolean; factories: Factory[] }>()
const emit = defineEmits<{ (e: 'update:open', v: boolean): void; (e: 'imported'): void }>()

const importing = ref(false)
const parsing = ref(false)
const importMode = ref<'file' | 'json'>('file')
const fileName = ref('')
const jsonText = ref('')
const previewRows = ref<ImportPreviewRow[]>([])
const selectedKeys = ref<Set<number>>(new Set())
const tableRef = ref<
  | {
      clearSelection: () => void
      toggleRowSelection: (row: ImportPreviewRow, selected?: boolean) => void
    }
  | null
>(null)
const skipDuplicates = ref(true)

const factoryNameById = computed(() => new Map(props.factories.map((f) => [f.id, f.name])))

const displayFactory = (row: ImportPreviewRow): string => {
  return (
    row.cleaned.factoryName ??
    (row.cleaned.factoryId ? factoryNameById.value.get(row.cleaned.factoryId) : '') ??
    row.cleaned.factoryId ??
    ''
  )
}

const hasPreview = computed(() => previewRows.value.length > 0)
const errorCount = computed(
  () => previewRows.value.filter((r) => r.issues.some((x) => x.severity === 'error')).length,
)
const warnCount = computed(() => previewRows.value.reduce((acc, r) => acc + r.issues.filter((x) => x.severity === 'warn').length, 0))
const selectedCount = computed(() => selectedKeys.value.size)
const duplicateCount = computed(() => previewRows.value.filter((r) => r.issues.some((x) => x.message.includes('订单号已存在'))).length)

const close = () => emit('update:open', false)

const reset = () => {
  parsing.value = false
  importing.value = false
  importMode.value = 'file'
  fileName.value = ''
  jsonText.value = ''
  previewRows.value = []
  selectedKeys.value = new Set()
  skipDuplicates.value = true
}

const syncTableSelection = async () => {
  await nextTick()
  if (!tableRef.value) return
  tableRef.value.clearSelection()
  for (const r of previewRows.value) {
    if (selectedKeys.value.has(r.index)) {
      tableRef.value.toggleRowSelection(r, true)
    }
  }
}

watch(
  () => props.open,
  async (v) => {
    if (!v) {
      reset()
      return
    }
  },
)

const onPickFile = async (file: File) => {
  parsing.value = true
  try {
    fileName.value = file.name
    const rawRows = await readSpreadsheetRows(file)
    const preview0 = buildImportPreview({ rawRows, factories: props.factories })
    const orderNos = preview0.rows.map((r) => r.cleaned.orderNo).filter((x): x is string => Boolean(x))
    let duplicates: string[] = []
    try {
      duplicates = orderNos.length > 0 ? await api.checkOrderDuplicates(orderNos) : []
    } catch {
      duplicates = []
    }
    const preview = buildImportPreview({
      rawRows,
      factories: props.factories,
      existingOrderNos: new Set(duplicates),
    })
    previewRows.value = preview.rows

    const selected = new Set<number>()
    for (const r of preview.rows) {
      const hasErrors = r.issues.some((x) => x.severity === 'error')
      const isDup = r.issues.some((x) => x.message.includes('订单号已存在'))
      if (!hasErrors && (!skipDuplicates.value || !isDup)) {
        selected.add(r.index)
      }
    }
    selectedKeys.value = selected
    await syncTableSelection()
  } catch (e) {
    ElMessage.error(e instanceof Error ? e.message : '解析失败')
  } finally {
    parsing.value = false
  }
}

const onUploadChange = async (uploadFile: { raw?: File }) => {
  const f = uploadFile.raw
  if (!f) return
  await onPickFile(f)
}

const onSkipDuplicatesChange = (v: boolean) => {
  skipDuplicates.value = v
  if (!hasPreview.value) return
  const selected = new Set(selectedKeys.value)
  for (const r of previewRows.value) {
    const isDup = r.issues.some((x) => x.message.includes('订单号已存在'))
    const hasErrors = r.issues.some((x) => x.severity === 'error')
    if (hasErrors) {
      selected.delete(r.index)
      continue
    }
    if (skipDuplicates.value && isDup) selected.delete(r.index)
    if (!skipDuplicates.value && !selected.has(r.index)) selected.add(r.index)
  }
  selectedKeys.value = selected
  void syncTableSelection()
}

const rowClassName = (args: { row: ImportPreviewRow }) => {
  const hasErrors = args.row.issues.some((x) => x.severity === 'error')
  return hasErrors ? 'bg-red-50' : ''
}

const isRowSelectable = (row: ImportPreviewRow) => !row.issues.some((x) => x.severity === 'error')

const onSelectionChange = (rows: ImportPreviewRow[]) => {
  selectedKeys.value = new Set(rows.map((r) => r.index))
}

const onDownloadTemplate = () => {
  const headers = [
    '订单号',
    'PO号',
    '产品名称',
    '国别',
    '订单金额',
    '下单日期',
    '客人货期',
    '工厂名称',
    '工厂货期',
    '合同状态',
    '订单进度',
    '备注',
  ]
  const csv = `${headers.join(',')}\n`
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = '订单导入模板.csv'
  a.click()
  URL.revokeObjectURL(a.href)
}

const onParseJson = async () => {
  parsing.value = true
  try {
    const t = jsonText.value.trim()
    if (!t) {
      ElMessage.warning('请粘贴JSON数据')
      return
    }
    const parsed = JSON.parse(t)
    if (!Array.isArray(parsed)) {
      ElMessage.error('JSON必须是数组')
      return
    }
    fileName.value = '粘贴JSON'
    const rawRows = parsed as Record<string, unknown>[]
    const preview0 = buildImportPreview({ rawRows, factories: props.factories })
    const orderNos = preview0.rows.map((r) => r.cleaned.orderNo).filter((x): x is string => Boolean(x))
    let duplicates: string[] = []
    try {
      duplicates = orderNos.length > 0 ? await api.checkOrderDuplicates(orderNos) : []
    } catch {
      duplicates = []
    }
    const preview = buildImportPreview({
      rawRows,
      factories: props.factories,
      existingOrderNos: new Set(duplicates),
    })
    previewRows.value = preview.rows

    const selected = new Set<number>()
    for (const r of preview.rows) {
      const hasErrors = r.issues.some((x) => x.severity === 'error')
      const isDup = r.issues.some((x) => x.message.includes('订单号已存在'))
      if (!hasErrors && (!skipDuplicates.value || !isDup)) selected.add(r.index)
    }
    selectedKeys.value = selected
    await syncTableSelection()
  } catch (e) {
    ElMessage.error(e instanceof Error ? e.message : 'JSON解析失败')
  } finally {
    parsing.value = false
  }
}

const toCreateInput = (row: ImportPreviewRow): Partial<Order> & { orderNo: string; productName: string } | null => {
  const c = row.cleaned
  if (!c.orderNo || !c.productName) return null
  const isDup = row.issues.some((x) => x.message.includes('订单号已存在'))
  if (skipDuplicates.value && isDup) return null
  return {
    orderNo: c.orderNo,
    poNo: c.poNo,
    productName: c.productName,
    country: c.country,
    orderAmount: c.orderAmount,
    orderDate: c.orderDate,
    customerDeliveryDate: c.customerDeliveryDate,
    factoryId: c.factoryId,
    factoryDeliveryDate: c.factoryDeliveryDate,
    factoryContract: c.factoryContract,
    packagingStatus: c.packagingStatus,
    stickerStatus: c.stickerStatus,
    shippingStatus: c.shippingStatus,
    inspectionStatus: c.inspectionStatus,
    purchaseAmount: c.purchaseAmount,
    orderProgress: c.orderProgress ?? '下单',
    remarks: c.remarks,
    ciAmount: c.ciAmount,
    etd: c.etd,
    eta: c.eta,
    paymentDate: c.paymentDate,
    paymentAmount: c.paymentAmount,
    balance: c.balance,
  }
}

const onImport = async () => {
  if (!hasPreview.value) {
    ElMessage.warning('请先选择文件')
    return
  }
  if (selectedKeys.value.size === 0) {
    ElMessage.warning('没有可导入的行')
    return
  }
  importing.value = true
  try {
    const items = previewRows.value
      .filter((r) => selectedKeys.value.has(r.index))
      .filter((r) => !r.issues.some((x) => x.severity === 'error'))
      .map((r) => toCreateInput(r))
      .filter(
        (x): x is Partial<Order> & { orderNo: string; productName: string } => x !== null,
      )

    const res = await api.bulkCreateOrders({ items, skipDuplicates: skipDuplicates.value })
    const skipped = res.skippedOrderNos.length
    ElMessage.success(`导入完成：成功 ${res.createdCount}，跳过重复 ${skipped}`)
    emit('imported')
    emit('update:open', false)
  } catch (e) {
    ElMessage.error(e instanceof Error ? e.message : '导入失败')
  } finally {
    importing.value = false
  }
}

const title = computed(() => (fileName.value ? `导入订单 - ${fileName.value}` : '导入订单'))
</script>

<template>
  <el-dialog :model-value="open" :title="title" width="1100px" @close="close">
    <div class="space-y-3">
      <el-radio-group v-model="importMode" size="small">
        <el-radio-button label="file">文件导入</el-radio-button>
        <el-radio-button label="json">粘贴JSON</el-radio-button>
      </el-radio-group>

      <div class="flex items-center gap-2">
        <el-upload
          v-if="importMode==='file'"
          :show-file-list="false"
          accept=".xlsx,.xls,.csv"
          :auto-upload="false"
          :on-change="onUploadChange"
        >
          <el-button type="primary" :loading="parsing">选择Excel/CSV</el-button>
        </el-upload>

        <el-button v-else type="primary" :loading="parsing" @click="onParseJson">解析JSON</el-button>
        <el-button @click="onDownloadTemplate">下载模板</el-button>
        <div class="flex-1" />
        <el-switch :model-value="skipDuplicates" @change="onSkipDuplicatesChange" />
        <span class="text-xs text-zinc-600">跳过重复订单号</span>
      </div>

      <el-input
        v-if="importMode==='json' && !hasPreview"
        v-model="jsonText"
        type="textarea"
        :rows="10"
        placeholder="粘贴 JSON 数组（例如 [{...},{...}]），字段支持 orderNo/poNo/product/country/factory/contractStatus/orderProgress/remarks 等"
      />

      <el-alert
        v-if="hasPreview"
        type="info"
        show-icon
        :closable="false"
        :title="`共 ${previewRows.length} 行；错误 ${errorCount} 行；警告 ${warnCount} 条；重复 ${duplicateCount} 行；已选择 ${selectedCount} 行导入`"
      />

      <el-table
        v-if="hasPreview"
        ref="tableRef"
        :data="previewRows"
        stripe
        class="w-full"
        height="520"
        :row-key="(r) => r.index"
        reserve-selection
        :row-class-name="rowClassName"
        @selection-change="onSelectionChange"
      >
        <el-table-column type="selection" width="48" :selectable="isRowSelectable" />
        <el-table-column prop="index" label="#" width="60" />
        <el-table-column label="订单号" min-width="140">
          <template #default="scope">
            <span>{{ scope.row.cleaned.orderNo }}</span>
          </template>
        </el-table-column>
        <el-table-column label="产品" min-width="160">
          <template #default="scope">
            <span>{{ scope.row.cleaned.productName }}</span>
          </template>
        </el-table-column>
        <el-table-column label="国别" width="100">
          <template #default="scope">
            <span>{{ scope.row.cleaned.country }}</span>
          </template>
        </el-table-column>
        <el-table-column label="工厂" width="160">
          <template #default="scope">
            <span>{{ displayFactory(scope.row) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="金额" width="120">
          <template #default="scope">
            <span>{{ scope.row.cleaned.orderAmount ?? '' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="下单" width="110">
          <template #default="scope">
            <span>{{ scope.row.cleaned.orderDate ?? '' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="客人货期" width="110">
          <template #default="scope">
            <span>{{ scope.row.cleaned.customerDeliveryDate ?? '' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="进度" width="110">
          <template #default="scope">
            <span>{{ scope.row.cleaned.orderProgress ?? '下单' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="合同" width="140">
          <template #default="scope">
            <span>{{ scope.row.cleaned.factoryContract ?? '' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="问题" min-width="260">
          <template #default="scope">
            <div class="space-y-1">
              <div v-for="(it, idx) in scope.row.issues" :key="idx" class="text-xs" :class="it.severity==='error' ? 'text-red-600' : 'text-amber-600'">
                {{ it.severity === 'error' ? '错误' : '警告' }}：{{ it.message }}
              </div>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <template #footer>
      <el-button @click="close">取消</el-button>
      <el-button v-if="hasPreview" @click="reset" :disabled="parsing || importing">清空</el-button>
      <el-button type="primary" :loading="importing" :disabled="parsing" @click="onImport">开始导入</el-button>
    </template>
  </el-dialog>
</template>

