<script setup lang="ts">
/**
 * 商品管理（SPU + SKU）
 *
 * 列表能力：
 *   - 关键字（商品名 / 品牌）、分类、状态、是否热门、是否新品 筛选
 *   - 多种排序：销量 / 起售价升降 / 创建时间
 *   - 分页、上下架/热门/新品 行内 toggle、删除
 *   - 行操作：编辑（弹窗）、调整库存（弹窗）
 *
 * 编辑弹窗：
 *   - SPU 基本信息（名称、品牌、分类、主图 URL、副图、详情）
 *   - SKU 列表（动态增删，至少 1 条；规格名不可重复）
 *   - 校验：名称 / 分类 / 至少 1 个 SKU
 */
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue'
import {
  Search,
  Refresh,
  Plus,
  Edit,
  Delete,
  Top,
  Star,
  Box,
  Picture,
  Plus as IconPlus,
  Minus as IconMinus
} from '@element-plus/icons-vue'
import {
  ElMessage,
  ElMessageBox,
  type FormInstance,
  type FormRules
} from 'element-plus'
import {
  getProductPageApi,
  getProductDetailApi,
  createProductApi,
  updateProductApi,
  deleteProductApi,
  updateProductStatusApi,
  updateProductHotApi,
  updateProductNewApi,
  adjustStockApi
} from '@/api/product'
import type {
  ProductItem,
  ProductDetail,
  ProductSavePayload,
  ProductSkuPayload,
  StockAdjustPayload
} from '@/api/product'
import { getCategoryOptionsApi } from '@/api/product'
import ImageUploader from '@/components/business/ImageUploader.vue'
import type { CategoryOption } from '@/api/product'
import { formatDate } from '@/utils/date'
import SearchBar from '@/components/common/SearchBar.vue'

// ============================================================
// 列表
// ============================================================
const loading = ref(false)
const list = ref<ProductItem[]>([])
const total = ref(0)

const query = reactive({
  current: 1,
  size: 10,
  keyword: '',
  categoryId: undefined as number | undefined,
  status: undefined as 0 | 1 | undefined,
  isHot: undefined as 0 | 1 | undefined,
  isNew: undefined as 0 | 1 | undefined,
  orderBy: 'create_desc' as 'sales_desc' | 'price_asc' | 'price_desc' | 'create_desc'
})

const ORDER_OPTIONS = [
  { label: '最新发布', value: 'create_desc' },
  { label: '销量降序', value: 'sales_desc' },
  { label: '价格升序', value: 'price_asc' },
  { label: '价格降序', value: 'price_desc' }
] as const

async function fetchData() {
  loading.value = true
  try {
    const res = await getProductPageApi(query)
    list.value = res.records
    total.value = res.total
  } finally {
    loading.value = false
  }
}

function handleSearch() {
  query.current = 1
  fetchData()
}

function handleReset() {
  query.keyword = ''
  query.categoryId = undefined
  query.status = undefined
  query.isHot = undefined
  query.isNew = undefined
  query.orderBy = 'create_desc'
  query.current = 1
  fetchData()
}

// 搜索栏的分类下拉：后端分页只支持叶子分类；这里用「启用状态分类选项」即可
const categoryOptions = ref<CategoryOption[]>([])
async function loadCategoryOptions() {
  try {
    categoryOptions.value = await getCategoryOptionsApi()
  } catch {
    /* ignore */
  }
}

// ============================================================
// 启停 / 热门 / 新品 行内切换（无确认弹窗）
// ============================================================
async function handleToggleStatus(row: any) {
  try {
    await updateProductStatusApi(row.id, row.status === 1 ? 0 : 1)
    ElMessage.success(row.status === 1 ? '已下架' : '已上架')
    fetchData()
  } catch { /* ignore */ }
}

function onStatusSwitchChange(row: any, v: boolean | number | string) {
  row.status = v ? 1 : 0
  handleToggleStatus(row)
}

async function handleToggleHot(row: any) {
  try {
    await updateProductHotApi(row.id, row.isHot === 1 ? 0 : 1)
    ElMessage.success(row.isHot === 1 ? '已取消热门' : '已设为热门')
    fetchData()
  } catch { /* ignore */ }
}

async function handleToggleNew(row: any) {
  try {
    await updateProductNewApi(row.id, row.isNew === 1 ? 0 : 1)
    ElMessage.success(row.isNew === 1 ? '已取消新品' : '已设为新品')
    fetchData()
  } catch { /* ignore */ }
}

// ============================================================
// 删除
// ============================================================
async function handleDelete(row: any) {
  await ElMessageBox.confirm(
    `确定要删除商品【${row.name}】吗？将级联删除其所有 SKU 规格。`,
    '提示',
    { type: 'warning' }
  )
  try {
    await deleteProductApi(row.id)
    ElMessage.success('删除成功')
    fetchData()
  } catch { /* ignore */ }
}

// ============================================================
// 编辑 / 发布（共用弹窗）
// ============================================================
const dialogVisible = ref(false)
const dialogMode = ref<'create' | 'edit'>('create')
const dialogTitle = computed(() => (dialogMode.value === 'edit' ? '编辑商品' : '发布商品'))
const formRef = ref<FormInstance>()
const submitting = ref(false)

interface SkuFormRow extends ProductSkuPayload {}

interface FormState {
  id?: number
  name: string
  categoryId: number | undefined
  brand: string
  mainImage: string
  /** 副图：URL 列表（保存时由前端序列化为 JSON 数组字符串） */
  subImages: string[]
  detail: string
  originPrice: number | undefined
  status: 0 | 1
  isHot: 0 | 1
  isNew: 0 | 1
  skuList: SkuFormRow[]
}

function emptySku(): SkuFormRow {
  return { skuName: '', price: 0, stock: 0, image: '', weight: 0, sort: 0 }
}

const form = reactive<FormState>({
  name: '',
  categoryId: undefined,
  brand: '',
  mainImage: '',
  subImages: [],
  detail: '',
  originPrice: undefined,
  status: 1,
  isHot: 0,
  isNew: 0,
  skuList: [emptySku()]
})

/** 副图独立 state 方便多图 UI 操作 */
const subImagesList = ref<string[]>([])

function addSubImage() {
  subImagesList.value.push('')
}

function updateSubImage(idx: number, url: string | undefined) {
  if (url) {
    subImagesList.value[idx] = url
  } else {
    subImagesList.value.splice(idx, 1)
  }
}

const rules = computed<FormRules<FormState>>(() => ({
  name: [
    { required: true, message: '请输入商品名称', trigger: 'blur' },
    { max: 200, message: '名称最长 200 字', trigger: 'blur' }
  ],
  categoryId: [
    {
      validator: (_r, val, cb) => (val == null ? cb(new Error('请选择分类')) : cb()),
      trigger: 'change'
    }
  ],
  skuList: [
    {
      validator: (_r, val, cb) => {
        if (!Array.isArray(val) || val.length === 0) return cb(new Error('至少需要一个 SKU'))
        const names = new Set<string>()
        for (const s of val) {
          if (!s.skuName) return cb(new Error('SKU 名称不能为空'))
          if (s.price == null || s.price < 0) return cb(new Error('SKU 价格必须 ≥ 0'))
          if (s.stock == null || s.stock < 0) return cb(new Error('SKU 库存必须 ≥ 0'))
          if (names.has(s.skuName)) return cb(new Error(`SKU 名称重复：${s.skuName}`))
          names.add(s.skuName)
        }
        cb()
      },
      trigger: 'blur'
    }
  ]
}))

function addSku() {
  form.skuList.push(emptySku())
}
function removeSku(idx: number) {
  if (form.skuList.length <= 1) {
    ElMessage.warning('至少需要 1 个 SKU')
    return
  }
  form.skuList.splice(idx, 1)
}

async function openCreate() {
  dialogMode.value = 'create'
  await nextTick()
  formRef.value?.resetFields()
  Object.assign(form, {
    id: undefined,
    name: '',
    categoryId: undefined,
    brand: '',
    mainImage: '',
    subImages: [],
    detail: '',
    originPrice: undefined,
    status: 1,
    isHot: 0,
    isNew: 0,
    skuList: [emptySku()]
  })
  subImagesList.value = []
  dialogVisible.value = true
}

async function openEdit(row: any) {
  dialogMode.value = 'edit'
  await nextTick()
  formRef.value?.resetFields()
  let detail: ProductDetail | null = null
  try {
    detail = await getProductDetailApi(row.id)
  } catch {
    detail = null
  }
  const d = detail ?? (row as unknown as ProductDetail)
  const subImgs: string[] = d.subImages || []
  Object.assign(form, {
    id: d.id,
    name: d.name ?? row.name,
    categoryId: d.categoryId ?? row.categoryId,
    brand: d.brand ?? '',
    mainImage: d.mainImage ?? row.mainImage ?? '',
    subImages: subImgs,
    detail: d.detail ?? '',
    originPrice: d.originPrice,
    status: (d.status ?? row.status) as 0 | 1,
    isHot: (d.isHot ?? row.isHot) as 0 | 1,
    isNew: (d.isNew ?? row.isNew) as 0 | 1,
    skuList:
      d.skuList && d.skuList.length
        ? d.skuList.map((s) => ({
            id: s.id,
            skuName: s.skuName,
            image: s.image ?? '',
            price: s.price,
            stock: s.stock,
            weight: s.weight ?? 0,
            sort: s.sort ?? 0
          }))
        : [emptySku()]
  })
  subImagesList.value = [...subImgs]
  dialogVisible.value = true
}

async function handleSubmit() {
  if (!formRef.value) return
  await formRef.value.validate(async (valid) => {
    if (!valid) return
    submitting.value = true
    try {
      // 副图：从独立 state 取（ImageUploader 直接操作）
      const subImagesArr = subImagesList.value.filter((s) => !!s)
      const payload: ProductSavePayload = {
        id: form.id,
        name: form.name,
        categoryId: form.categoryId!,
        brand: form.brand,
        mainImage: form.mainImage,
        subImages: JSON.stringify(subImagesArr),
        detail: form.detail,
        originPrice: form.originPrice,
        status: form.status,
        isHot: form.isHot,
        isNew: form.isNew,
        skuList: form.skuList.map((s, idx) => ({
          id: s.id,
          skuName: s.skuName,
          image: s.image,
          price: s.price,
          stock: s.stock,
          weight: s.weight,
          sort: s.sort ?? idx
        }))
      }
      if (dialogMode.value === 'create') {
        await createProductApi(payload)
        ElMessage.success('发布成功')
      } else {
        await updateProductApi(payload)
        ElMessage.success('更新成功')
      }
      dialogVisible.value = false
      await fetchData()
    } catch { /* 拦截器已提示 */ } finally {
      submitting.value = false
    }
  })
}

// ============================================================
// 调整库存（单 SKU）
// ============================================================
const stockDialogVisible = ref(false)
const stockTarget = ref<ProductItem | null>(null)
const stockForm = reactive<{ mode: 'delta' | 'target'; value: number }>({
  mode: 'delta',
  value: 0
})

function openAdjustStock(row: any) {
  stockTarget.value = row
  stockForm.mode = 'delta'
  stockForm.value = 0
  stockDialogVisible.value = true
}

async function handleAdjustStock() {
  if (!stockTarget.value) return
  if (stockForm.value === 0) {
    ElMessage.warning('调整值不能为 0')
    return
  }
  // 需要后端真实 SKU ID；列表项不带。这里走 SKU 列表拿到第一个
  try {
    const detail = await getProductDetailApi(stockTarget.value.id)
    const sku = detail.skuList?.[0]
    if (!sku) {
      ElMessage.error('该商品没有可调整的 SKU')
      return
    }
    const payload: StockAdjustPayload =
      stockForm.mode === 'delta'
        ? { skuId: sku.id, delta: stockForm.value }
        : { skuId: sku.id, targetStock: stockForm.value }
    await adjustStockApi(payload)
    ElMessage.success('库存已调整')
    stockDialogVisible.value = false
    fetchData()
  } catch { /* ignore */ }
}

onMounted(() => {
  loadCategoryOptions()
  fetchData()
})

// 给筛选下拉一个空选项提示
watch(categoryOptions, (v) => {
  if (v.length === 0) {
    // 静默不报错
  }
}, { immediate: true })
</script>

<template>
  <div class="page-container">
    <div class="page-header">
      <div>
        <h2>商品列表</h2>
        <p class="page-desc">管理零食商城所有商品（SPU + 多规格 SKU），支持上下架 / 热门 / 新品 / 库存</p>
      </div>
      <el-button type="primary" :icon="Plus" @click="openCreate">发布商品</el-button>
    </div>

    <el-card shadow="never" class="table-card">
      <SearchBar show-divider>
        <el-input
          v-model="query.keyword"
          placeholder="商品名 / 品牌"
          :prefix-icon="Search"
          clearable
          style="width: 200px"
          @keyup.enter="handleSearch"
        />
        <el-select
          v-model="query.categoryId"
          placeholder="分类"
          clearable
          filterable
          style="width: 160px"
        >
          <el-option
            v-for="c in categoryOptions"
            :key="c.id"
            :label="c.name"
            :value="c.id"
          />
        </el-select>
        <el-select v-model="query.status" placeholder="状态" clearable style="width: 120px">
          <el-option label="已上架" :value="1" />
          <el-option label="已下架" :value="0" />
        </el-select>
        <el-select v-model="query.isHot" placeholder="热门" clearable style="width: 110px">
          <el-option label="热门" :value="1" />
          <el-option label="非热门" :value="0" />
        </el-select>
        <el-select v-model="query.isNew" placeholder="新品" clearable style="width: 110px">
          <el-option label="新品" :value="1" />
          <el-option label="非新品" :value="0" />
        </el-select>
        <el-select v-model="query.orderBy" placeholder="排序" style="width: 140px">
          <el-option v-for="o in ORDER_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
        </el-select>
        <el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
        <el-button :icon="Refresh" @click="handleReset">重置</el-button>
      </SearchBar>

      <el-table v-loading="loading" :data="list" stripe border>
        <el-table-column type="index" label="#" width="60" align="center" />
        <el-table-column label="商品" min-width="260">
          <template #default="{ row }">
            <div class="product-cell">
              <el-image
                :src="row.mainImage"
                fit="cover"
                class="cell-image"
                :preview-src-list="row.mainImage ? [row.mainImage] : []"
                preview-teleported
                hide-on-click-modal
              >
                <template #error>
                  <div class="image-error"><el-icon><Picture /></el-icon></div>
                </template>
              </el-image>
              <div class="product-meta">
                <div class="product-name">{{ row.name }}</div>
                <div class="product-sub">
                  <span v-if="row.brand" class="brand">{{ row.brand }}</span>
                  <el-tag v-if="row.isHot === 1" type="danger" size="small" effect="plain">热门</el-tag>
                  <el-tag v-if="row.isNew === 1" type="success" size="small" effect="plain">新品</el-tag>
                </div>
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="分类" min-width="120">
          <template #default="{ row }">
            <span class="muted">{{ row.categoryName || '—' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="价格区间" width="140" align="center">
          <template #default="{ row }">
            <span v-if="row.minPrice != null">¥{{ row.minPrice }}</span>
            <span v-else class="muted">—</span>
            <span v-if="row.maxPrice != null && row.maxPrice !== row.minPrice"> ~ ¥{{ row.maxPrice }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="totalStock" label="库存" width="90" align="center" />
        <el-table-column prop="sales" label="销量" width="90" align="center" />
        <el-table-column label="状态" width="120" align="center">
          <template #default="{ row }">
            <el-switch
              :model-value="row.status === 1"
              :active-value="true"
              :inactive-value="false"
              active-text="上架"
              inactive-text="下架"
              inline-prompt
              @change="(v) => onStatusSwitchChange(row, v)"
            />
          </template>
        </el-table-column>
        <el-table-column label="创建时间" width="170">
          <template #default="{ row }">{{ formatDate(row.createTime) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="320" align="center" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" size="small" :icon="Edit" @click="openEdit(row)">
              编辑
            </el-button>
            <el-button link type="primary" size="small" :icon="Box" @click="openAdjustStock(row)">
              库存
            </el-button>
            <el-button
              link
              :type="row.isHot === 1 ? 'warning' : 'info'"
              size="small"
              :icon="Star"
              @click="handleToggleHot(row)"
            >
              {{ row.isHot === 1 ? '取消热门' : '热门' }}
            </el-button>
            <el-button
              link
              :type="row.isNew === 1 ? 'success' : 'info'"
              size="small"
              :icon="Top"
              @click="handleToggleNew(row)"
            >
              {{ row.isNew === 1 ? '取消新品' : '新品' }}
            </el-button>
            <el-button link type="danger" size="small" :icon="Delete" @click="handleDelete(row)">
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination-wrapper">
        <el-pagination
          v-model:current-page="query.current"
          v-model:page-size="query.size"
          :total="total"
          :page-sizes="[10, 20, 50]"
          layout="total, sizes, prev, pager, next, jumper"
          background
          @current-change="fetchData"
          @size-change="fetchData"
        />
      </div>
    </el-card>

    <!-- 发布 / 编辑弹窗 -->
    <el-dialog
      v-model="dialogVisible"
      :title="dialogTitle"
      width="900px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
        <el-row :gutter="16">
          <el-col :span="16">
            <el-form-item label="商品名称" prop="name">
              <el-input v-model="form.name" placeholder="如：原味夏威夷果 500g" maxlength="200" show-word-limit />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="品牌">
              <el-input v-model="form.brand" placeholder="可选" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="分类" prop="categoryId">
              <el-select
                v-model="form.categoryId"
                placeholder="选择分类"
                filterable
                style="width: 100%"
              >
                <el-option
                  v-for="c in categoryOptions"
                  :key="c.id"
                  :label="c.name"
                  :value="c.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="原价">
              <el-input-number
                v-model="form.originPrice"
                :min="0"
                :precision="2"
                :step="1"
                controls-position="right"
                placeholder="划线价，可选"
              />
            </el-form-item>
          </el-col>
        </el-row>

        <el-form-item label="主图">
          <ImageUploader v-model="form.mainImage" biz-type="product" :max-size="5" />
        </el-form-item>

        <el-form-item label="副图">
          <div class="sub-images">
            <div
              v-for="(img, idx) in subImagesList"
              :key="idx"
              class="sub-image-item"
            >
              <ImageUploader
                :model-value="img"
                biz-type="product"
                :max-size="5"
                @update:modelValue="(v) => updateSubImage(idx, v)"
              />
            </div>
            <el-button
              v-if="subImagesList.length < 5"
              type="primary"
              plain
              :icon="Plus"
              @click="addSubImage"
            >
              添加副图
            </el-button>
          </div>
        </el-form-item>        <el-form-item label="商品详情">
          <el-input
            v-model="form.detail"
            type="textarea"
            :rows="4"
            placeholder="支持 HTML（图片 / 段落 / 列表）"
          />
        </el-form-item>

        <el-form-item label="属性">
          <el-space wrap>
            <el-switch v-model="form.status" :active-value="1" :inactive-value="0" active-text="上架" inactive-text="下架" />
            <el-switch v-model="form.isHot" :active-value="1" :inactive-value="0" active-text="热门" inactive-text="非热门" />
            <el-switch v-model="form.isNew" :active-value="1" :inactive-value="0" active-text="新品" inactive-text="非新品" />
          </el-space>
        </el-form-item>

        <el-form-item label="SKU 规格" prop="skuList">
          <div class="sku-list">
            <div
              v-for="(sku, idx) in form.skuList"
              :key="idx"
              class="sku-row"
            >
              <el-input
                v-model="sku.skuName"
                placeholder="规格名（如：原味/500g）"
                style="width: 180px"
              />
              <el-input-number
                v-model="sku.price"
                :min="0"
                :precision="2"
                :step="1"
                controls-position="right"
                style="width: 140px"
                placeholder="价格"
              />
              <el-input-number
                v-model="sku.stock"
                :min="0"
                :step="1"
                controls-position="right"
                style="width: 120px"
                placeholder="库存"
              />
              <el-input-number
                v-model="sku.weight"
                :min="0"
                :step="1"
                controls-position="right"
                style="width: 110px"
                placeholder="克重（可选）"
              />
              <el-input-number
                v-model="sku.sort"
                :min="0"
                :step="1"
                controls-position="right"
                style="width: 100px"
                placeholder="排序"
              />
              <el-button
                link
                type="danger"
                :icon="IconMinus"
                :disabled="form.skuList.length <= 1"
                @click="removeSku(idx)"
              >
                移除
              </el-button>
            </div>
            <el-button
              type="primary"
              plain
              :icon="IconPlus"
              @click="addSku"
              class="add-sku-btn"
            >
              添加 SKU
            </el-button>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>

    <!-- 调整库存弹窗 -->
    <el-dialog
      v-model="stockDialogVisible"
      title="调整库存"
      width="420px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form label-width="90px" v-if="stockTarget">
        <el-form-item label="商品">
          <span class="target-text">
            {{ stockTarget.name }}（{{ stockTarget.totalStock ?? 0 }} 件）
          </span>
        </el-form-item>
        <el-form-item label="调整方式">
          <el-radio-group v-model="stockForm.mode">
            <el-radio value="delta">增量（正加负减）</el-radio>
            <el-radio value="target">绝对值</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="数值">
          <el-input-number
            v-model="stockForm.value"
            :min="stockForm.mode === 'target' ? 0 : -99999"
            :step="1"
            controls-position="right"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="stockDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleAdjustStock">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.sub-images {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-start;
}
.sub-image-item {
  width: 120px;
  height: 120px;
}
.product-cell {
  display: flex;
  align-items: center;
  gap: 10px;
}
.product-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.product-name {
  font-weight: 500;
  color: $color-text-primary;
  line-height: 1.4;
}
.product-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  .brand {
    color: $color-text-secondary;
  }
}
.cell-image {
  width: 48px;
  height: 48px;
  border-radius: 6px;
  flex-shrink: 0;
}
.image-error {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #c0c4cc;
  background: $bg-page;
  border-radius: 6px;
}
.muted {
  color: $color-text-secondary;
}
.pagination-wrapper {
  display: flex;
  justify-content: flex-end;
  padding: 16px 20px;
}

.sku-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}
.sku-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.add-sku-btn {
  align-self: flex-start;
}
.target-text {
  color: $color-text-primary;
  font-weight: 500;
}
</style>
