<script setup lang="ts">
/**
 * 商品分类管理（管理端）
 *
 * 后端契约（见 /api/admin/category/**），由 src/api/product.ts 统一封装。
 * 数据结构：树形（最多三级），通过 el-table :tree-props="{ children: 'children' }" 渲染。
 */
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import { Plus, Edit, Delete } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
import {
  getCategoryTreeApi,
  createCategoryApi,
  updateCategoryApi,
  deleteCategoryApi,
  updateCategoryStatusApi,
  updateCategorySortApi
} from '@/api/product'
import type { CategoryTreeNode, CategorySavePayload } from '@/api/product'

const tree = ref<CategoryTreeNode[]>([])
const loading = ref(false)
const searchKeyword = ref('')

/** 过滤后的树（前端按 name 模糊过滤，保留结构） */
const filteredTree = computed<CategoryTreeNode[]>(() => {
  const kw = searchKeyword.value.trim().toLowerCase()
  if (!kw) return tree.value
  const filter = (nodes: CategoryTreeNode[]): CategoryTreeNode[] => {
    const out: CategoryTreeNode[] = []
    for (const n of nodes) {
      const matched = n.name.toLowerCase().includes(kw)
      const children = n.children ? filter(n.children) : []
      if (matched || children.length) {
        out.push({ ...n, children: children.length ? children : n.children })
      }
    }
    return out
  }
  return filter(tree.value)
})

async function fetchData() {
  loading.value = true
  try {
    tree.value = await getCategoryTreeApi()
  } finally {
    loading.value = false
  }
}

// ============================================================
// 新增 / 编辑 / 新增子分类 — 共用一个弹窗
// ============================================================
const dialogVisible = ref(false)
const dialogMode = ref<'create' | 'edit'>('create')
const dialogTitle = computed(() => (dialogMode.value === 'edit' ? '编辑分类' : '新增分类'))
const formRef = ref<FormInstance>()
const submitting = ref(false)

const parentOptions = ref<{ id: number; name: string; level: number; parentId: number }[]>([])

interface FormState {
  id?: number
  name: string
  parentId: number
  level: 1 | 2 | 3
  sort: number
  icon: string
  status: 0 | 1
}
const form = reactive<FormState>({
  name: '',
  parentId: 0,
  level: 1,
  sort: 0,
  icon: '',
  status: 1
})

const rules: FormRules<FormState> = {
  name: [
    { required: true, message: '请输入分类名称', trigger: 'blur' },
    { max: 50, message: '名称最长 50 字', trigger: 'blur' }
  ],
  level: [{ required: true, message: '请选择层级', trigger: 'change' }],
  sort: [{ required: true, message: '请输入排序号', trigger: 'blur' }]
}

/**
 * 父分类 ID → 推断层级
 *   parentId = 0       → 一级分类
 *   parent.level = 1   → 二级分类
 *   parent.level = 2   → 三级分类
 *   parent.level = 3   → 不允许再创建子分类
 */
function deriveLevelByParent(parentId: number): 1 | 2 | 3 | null {
  if (parentId === 0) return 1
  const findIn = (nodes: CategoryTreeNode[]): CategoryTreeNode | null => {
    for (const n of nodes) {
      if (n.id === parentId) return n
      const child = n.children ? findIn(n.children) : null
      if (child) return child
    }
    return null
  }
  const parent = findIn(tree.value)
  if (!parent) return 1
  if (parent.level === 1) return 2
  if (parent.level === 2) return 3
  return null // 三级分类下不允许再创建
}

async function openCreateDialog(parentId = 0) {
  const level = deriveLevelByParent(parentId)
  if (level === null) {
    ElMessage.warning('三级分类下不允许再创建子分类')
    return
  }
  dialogMode.value = 'create'
  formRef.value?.resetFields()
  Object.assign(form, {
    id: undefined,
    name: '',
    parentId,
    level,
    sort: 0,
    icon: '',
    status: 1
  })
  await loadParentOptions(level)
  dialogVisible.value = true
}

async function openEditDialog(row: any) {
  dialogMode.value = 'edit'
  await nextTick()
  formRef.value?.resetFields()
  Object.assign(form, {
    id: row.id,
    name: row.name,
    parentId: row.parentId ?? 0,
    level: row.level,
    sort: row.sort ?? 0,
    icon: row.icon ?? '',
    status: row.status
  })
  await loadParentOptions(row.level)
  dialogVisible.value = true
}

async function loadParentOptions(level: number) {
  // 父分类只能是 level-1 的分类
  // level=1 → 顶级，父选项就是「无」
  // level=2 → 父分类必须是 level=1
  // level=3 → 父分类必须是 level=2
  const all = await getCategoryTreeApi()
  const flat: { id: number; name: string; level: number; parentId: number }[] = []
  const walk = (nodes: CategoryTreeNode[]) => {
    for (const n of nodes) {
      flat.push({ id: n.id, name: n.name, level: n.level, parentId: n.parentId ?? 0 })
      if (n.children) walk(n.children)
    }
  }
  walk(all)
  parentOptions.value = flat.filter((c) => c.level === level - 1)
}

async function handleSubmit() {
  if (!formRef.value) return
  await formRef.value.validate(async (valid) => {
    if (!valid) return
    submitting.value = true
    try {
      const payload: CategorySavePayload = {
        id: form.id,
        name: form.name,
        parentId: form.parentId,
        level: form.level,
        sort: form.sort,
        icon: form.icon,
        status: form.status
      }
      if (dialogMode.value === 'create') {
        await createCategoryApi(payload)
        ElMessage.success('新增成功')
      } else {
        await updateCategoryApi(payload)
        ElMessage.success('更新成功')
      }
      dialogVisible.value = false
      await fetchData()
    } catch {
      /* 拦截器已提示 */
    } finally {
      submitting.value = false
    }
  })
}

// ============================================================
// 启用 / 禁用
// ============================================================
async function handleStatusChange(row: any, val: 0 | 1) {
  try {
    await updateCategoryStatusApi(row.id, val)
    ElMessage.success(val === 1 ? '已启用' : '已禁用')
    await fetchData()
  } catch {
    // 回滚开关
    row.status = val === 1 ? 0 : 1
  }
}

// ============================================================
// 排序（行内编辑，blur 提交）
// ============================================================
async function handleSortBlur(row: any) {
  if (row.sort == null) return
  try {
    await updateCategorySortApi(row.id, row.sort)
    ElMessage.success('排序已更新')
  } catch {
    /* 拦截器已提示 */
  }
}

// ============================================================
// 删除
// ============================================================
async function handleDelete(row: any) {
  await ElMessageBox.confirm(
    `确定要删除分类【${row.name}】吗？${row.children?.length ? '该分类下还有子分类，将一并删除。' : ''}`,
    '提示',
    { type: 'warning' }
  )
  try {
    await deleteCategoryApi(row.id)
    ElMessage.success('删除成功')
    await fetchData()
  } catch {
    /* 拦截器已提示 */
  }
}

onMounted(fetchData)
</script>

<template>
  <div class="page-container">
    <div class="page-header">
      <div>
        <h2>商品分类</h2>
        <p class="page-desc">树形结构管理商品分类，最多支持三级嵌套</p>
      </div>
      <el-button type="primary" :icon="Plus" @click="openCreateDialog(0)">新增分类</el-button>
    </div>

    <el-card shadow="never" v-loading="loading">
      <div class="toolbar">
        <el-input
          v-model="searchKeyword"
          placeholder="搜索分类名称"
          clearable
          style="width: 240px"
        />
        <el-button @click="fetchData">刷新</el-button>
      </div>

      <el-table
        :data="filteredTree"
        row-key="id"
        :tree-props="{ children: 'children' }"
        default-expand-all
        :key="searchKeyword"
        border
        stripe
      >
        <el-table-column prop="name" label="分类名称" min-width="240">
          <template #default="{ row }">
            <span :class="{ 'is-disabled': row.status === 0 }">{{ row.name }}</span>
            <el-tag v-if="row.status === 0" type="info" size="small" style="margin-left: 8px">
              已禁用
            </el-tag>
          </template>
        </el-table-column>

        <el-table-column label="层级" width="120" align="center">
          <template #default="{ row }">
            <el-tag :type="row.level === 1 ? 'primary' : row.level === 2 ? 'success' : 'warning'" size="small">
              {{ ['一级', '二级', '三级'][row.level - 1] }}分类
            </el-tag>
          </template>
        </el-table-column>

        <el-table-column label="排序" width="140" align="center">
          <template #default="{ row }">
            <el-input-number
              v-model="row.sort"
              :min="0"
              :max="9999"
              size="small"
              controls-position="right"
              style="width: 100px"
              @blur="handleSortBlur(row)"
              @change="(_v: number | undefined) => handleSortBlur(row)"
            />
          </template>
        </el-table-column>

        <el-table-column label="状态" width="100" align="center">
          <template #default="{ row }">
            <el-switch
              :model-value="row.status === 1"
              :active-value="true"
              :inactive-value="false"
              @change="(v: boolean | number | string) => handleStatusChange(row, v ? 1 : 0)"
            />
          </template>
        </el-table-column>

        <el-table-column label="操作" width="280" align="center" fixed="right">
          <template #default="{ row }">
            <el-button
              link
              type="primary"
              size="small"
              :icon="Plus"
              :disabled="row.level >= 3"
              @click="openCreateDialog(row.id)"
            >
              新增子分类
            </el-button>
            <el-button link type="primary" size="small" :icon="Edit" @click="openEditDialog(row)">
              编辑
            </el-button>
            <el-button link type="danger" size="small" :icon="Delete" @click="handleDelete(row)">
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 新增 / 编辑弹窗 -->
    <el-dialog
      v-model="dialogVisible"
      :title="dialogTitle"
      width="520px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="90px"
        label-position="right"
      >
        <el-form-item label="分类名称" prop="name">
          <el-input v-model="form.name" placeholder="如：坚果炒货" maxlength="50" show-word-limit />
        </el-form-item>

        <el-form-item label="层级" prop="level">
          <el-radio-group v-model="form.level" :disabled="dialogMode === 'edit'">
            <el-radio :value="1">一级</el-radio>
            <el-radio :value="2">二级</el-radio>
            <el-radio :value="3">三级</el-radio>
          </el-radio-group>
          <div class="form-tip">层级在创建后不可修改</div>
        </el-form-item>

        <el-form-item label="父分类" prop="parentId">
          <el-select
            v-model="form.parentId"
            placeholder="选择父分类"
            :disabled="form.level === 1"
            style="width: 100%"
          >
            <el-option
              v-for="opt in parentOptions"
              :key="opt.id"
              :label="opt.name"
              :value="opt.id"
            />
          </el-select>
          <div v-if="form.level === 1" class="form-tip">一级分类无父级</div>
        </el-form-item>

        <el-form-item label="排序" prop="sort">
          <el-input-number v-model="form.sort" :min="0" :max="9999" controls-position="right" />
          <div class="form-tip">数字越小排序越靠前</div>
        </el-form-item>

        <el-form-item label="图标" prop="icon">
          <el-input v-model="form.icon" placeholder="图标 URL（可选）" />
        </el-form-item>

        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio :value="1">启用</el-radio>
            <el-radio :value="0">禁用</el-radio>
          </el-radio-group>
        </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>
  </div>
</template>

<style lang="scss" scoped>
.toolbar {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
  align-items: center;
}

.is-disabled {
  color: $color-text-secondary;
  text-decoration: line-through;
}

.form-tip {
  font-size: 12px;
  color: $color-text-secondary;
  margin-top: 4px;
  line-height: 1.4;
}
</style>
