<template>
  <el-tabs v-model="tabName" type="border-card" tab-position="top" v-loading="formLoading">
    <el-tab-pane label="商品信息" name="basic">
      <el-form :model="form" ref="spuForm" :rules="rules" label-width="90px">
        <el-row :gutter="20">
          <el-col :span="8" :offset="0">
            <el-form-item label="产品名称" prop="productName">
              <el-input v-model="form.productName" placeholder="请输入产品名称" />
            </el-form-item>
          </el-col>
          <el-col :span="8" :offset="0">
            <el-form-item label="分类" prop="productCategory">
              <el-cascader
                :options="opts.category"
                v-model="form.productCategory"
                placeholder="请选择分类"
                :props="{ label: 'name', value: 'id' }"
                filterable
                show-all-levels
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8" :offset="0">
            <el-form-item label="品牌" prop="productBrand">
              <el-select v-model="form.productBrand" placeholder="请选择品牌" filterable>
                <el-option
                  v-for="item in opts.brand"
                  :key="item.brandId"
                  :label="item.name"
                  :value="item.brandId"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col
            :span="8"
            :offset="0"
            v-for="fieldItem in diyFieldList"
            :key="fieldItem.clueParamId"
          >
            <el-form-item :label="fieldItem.label" :prop="fieldItem.field">
              <component :is="componentMap[fieldItem.component]" v-model="form[fieldItem.field]">
                <template v-if="fieldItem.component == 'Select'">
                  <el-option
                    v-for="item in fieldItem.options"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                  />
                </template>
                <template v-else-if="fieldItem.component == 'Radio'">
                  <el-radio v-for="item in fieldItem.options" :key="item.id" :label="item.id">
                    {{ item.name }}
                  </el-radio>
                </template>
                <template v-else-if="fieldItem.component == 'Checkbox'">
                  <el-checkbox
                    v-for="item in fieldItem.options"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                  />
                </template>
              </component>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12" :offset="0">
            <el-form-item label="产品简介" prop="productIntro">
              <el-input
                v-model="form.productIntro"
                type="textarea"
                :autosize="{ minRows: 4 }"
                placeholder="请输入产品简介"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12" :offset="0">
            <el-form-item label="主图" prop="mainImage">
              <UploadImg v-model="form.mainImage" height="100px" width="100px" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20" v-if="!formLoading">
          <el-col :span="24" :offset="0">
            <el-form-item label="轮播图" prop="carouselImages">
              <UploadImgs v-model="form.carouselImages" height="100px" width="100px" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24" :offset="0">
            <el-form-item label="商品规格">
              <el-button @click="handleAddSpec">添加规格</el-button>
              <el-col v-for="(item, index) in form.productSpecList" :key="index">
                <div>
                  <el-text class="mx-1">属性名：</el-text>
                  <el-tag class="mx-1" closable type="success" @close="handleCloseProperty(index)"
                    >{{ item.name }}
                  </el-tag>
                </div>
                <div>
                  <el-text class="mx-1">属性值：</el-text>
                  <el-tag
                    v-for="(value, valueIndex) in item.values"
                    :key="value.id"
                    class="mx-1"
                    closable
                    @close="handleCloseValue(index, valueIndex)"
                  >
                    {{ value.name }}
                  </el-tag>
                  <el-input
                    v-show="inputVisible(index)"
                    :id="`input${index}`"
                    :ref="setInputRef"
                    v-model="inputValue"
                    class="!w-20"
                    size="small"
                    @blur="handleInputConfirm(index, item.id)"
                    @keyup.enter="handleInputConfirm(index, item.id)"
                  />
                  <el-button
                    v-show="!inputVisible(index)"
                    class="button-new-tag ml-1"
                    size="small"
                    @click="showInput(index)"
                  >
                    + 添加
                  </el-button>
                </div>
                <el-divider class="my-10px" />
              </el-col>
            </el-form-item>
            <el-form-item>
              <el-table :data="form.skuList">
                <el-table-column type="index" width="50" />
                <el-table-column prop="specsName" label="规格名称">
                  <template #default="{ row }">
                    <el-input v-model="row.specsName" placeholder="请输入" />
                  </template>
                </el-table-column>
                <el-table-column
                  v-for="(col, index) in form.productSpecList"
                  :key="col.id"
                  :label="col.name"
                >
                  <template #default="{ row }">
                    <span style="font-weight: bold; color: #40aaff">
                      {{ row.properties[index]?.valueName }}
                    </span>
                  </template>
                </el-table-column>
                <el-table-column prop="price" label="销售价">
                  <template #default="{ row }">
                    <el-input-number v-model="row.price" :min="0.01" :step="1" />
                  </template>
                </el-table-column>
                <el-table-column prop="intro" label="简介">
                  <template #default="{ row }">
                    <el-input v-model="row.intro" placeholder="请输入简介" />
                  </template>
                </el-table-column>
              </el-table>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </el-tab-pane>
    <el-tab-pane label="详细信息" name="detail">
      <Editor v-model:modelValue="form.detailInfo" />
    </el-tab-pane>
  </el-tabs>
  <div class="mt-20px flex justify-center">
    <el-button type="primary" @click="onSubmit">保存</el-button>
    <el-button plain @click="router.replace('/MiniMall/product')">返回列表</el-button>
  </div>
  <ProductAttributesAddForm ref="attributesAddFormRef" :propertyList="form.productSpecList" />
</template>

<script setup>
import { cloneDeep } from 'lodash-es'
import { getDiyFieldList } from '@/api/mall/product/productField'
import * as PropertyApi from '@/api/mall/product/property'
import * as ProductApi from '@/api/mall/product/index'
import ProductAttributesAddForm from './Comp/ProductAttributesAddForm.vue'
import * as BrandApi from '@/api/mall/product/brand'
import * as CategoryApi from '@/api/mall/product/category'
import { handleTree } from '@/utils/tree'
import { isObject } from '@/utils/is.ts'
import { componentMap } from '@/components/Form/src/componentMap'

const route = useRoute()
const router = useRouter()
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化

const tabName = ref('basic')
const form = ref({
  productName: undefined,
  productCategory: undefined,
  productBrand: undefined,
  productIntro: undefined,
  mainImage: '',
  carouselImages: [],
  productSpecList: [],
  skuList: [],
  detailInfo: null,
  status: 0
})
const rules = {
  productName: { required: true, message: '产品名称不可为空', trigger: 'blur' }
}
const attributesAddFormRef = ref() // 添加商品属性表单

const opts = ref({
  brand: [],
  category: []
})

const diyFieldList = ref([])
async function getOptions() {
  getDiyFieldList().then((data) => {
    diyFieldList.value = data
  })
  BrandApi.getSimpleBrandList().then((data) => {
    opts.value.brand = data || []
  })
  CategoryApi.getCategorySimpleList().then((data) => {
    opts.value.category = handleTree(data || [])
  })
}

/** 删除属性*/
function handleCloseProperty(index) {
  form.value.productSpecList?.splice(index, 1)
  getTableList()
}

const attributeIndex = ref(null)
// 输入框显隐控制
const inputVisible = computed(() => (index) => {
  if (attributeIndex.value === null) return false
  if (attributeIndex.value === index) return true
})

const inputValue = ref('') // 输入框值
/** 输入框失去焦点或点击回车时触发 */
async function handleInputConfirm(index, propertyId) {
  if (inputValue.value) {
    // 保存属性值
    try {
      const id = await PropertyApi.createPropertyValue({ propertyId, name: inputValue.value })
      form.value.productSpecList[index].values.push({ id, name: inputValue.value })
      message.success('添加成功')
    } catch {
      message.error('添加失败，请重试')
    }
  }
  attributeIndex.value = null
  inputValue.value = ''
  getTableList()
}

/** 删除属性值*/
function handleCloseValue(index, valueIndex) {
  form.value.productSpecList[index].values?.splice(valueIndex, 1)
  getTableList()
}

function getTableList() {
  const propertyList = [...form.value.productSpecList]
  // 构建数据结构
  const propertyValues = propertyList.map((item) =>
    item.values.map((v) => ({
      propertyId: item.id,
      propertyName: item.name,
      valueId: v.id,
      valueName: v.name
    }))
  )
  const buildSkuList = build(propertyValues)
  // 如果回显的 sku 属性和添加的属性不一致则重置 skuList 列表
  if (!validateData(propertyList)) {
    // 如果不一致则重置表数据，默认添加新的属性重新生成 sku 列表
    // form.value.skuList = []
  }
  form.value.skuList = []
  for (const item of buildSkuList) {
    const row = {
      properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个 property 对象
      price: 0.01,
      intro: '',
      specsName: ''
    }
    // 如果存在属性相同的 sku 则不做处理
    const index = form.value.skuList.findIndex(
      (sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties)
    )
    if (index !== -1) {
      continue
    }
    form.value.skuList.push(row)
  }
}

/**
 * 生成 skuList 前置校验
 */
const validateData = (propertyList) => {
  const skuPropertyIds = []
  form.value.skuList.forEach((sku) =>
    sku.properties.map((property) => {
      if (skuPropertyIds.indexOf(property.propertyId) === -1) {
        skuPropertyIds.push(property.propertyId)
      }
    })
  )
  const propertyIds = propertyList.map((item) => item.id)
  return skuPropertyIds.length === propertyIds.length
}

/** 构建所有排列组合 */
const build = (propertyValuesList) => {
  if (propertyValuesList.length === 0) {
    return []
  } else if (propertyValuesList.length === 1) {
    return propertyValuesList[0]
  } else {
    const result = []
    const rest = build(propertyValuesList.slice(1))
    for (let i = 0; i < propertyValuesList[0].length; i++) {
      for (let j = 0; j < rest.length; j++) {
        // 第一次不是数组结构，后面的都是数组结构
        if (Array.isArray(rest[j])) {
          result.push([propertyValuesList[0][i], ...rest[j]])
        } else {
          result.push([propertyValuesList[0][i], rest[j]])
        }
      }
    }
    return result
  }
}

const inputRef = ref([]) //标签输入框Ref
/** 显示输入框并获取焦点 */
const showInput = async (index) => {
  attributeIndex.value = index
  inputRef.value[index].focus()
}

/** 解决 ref 在 v-for 中的获取问题*/
const setInputRef = (el) => {
  if (el === null || typeof el === 'undefined') return
  // 如果不存在id相同的元素才添加
  if (!inputRef.value.some((item) => item.input?.attributes.id === el.input?.attributes.id)) {
    inputRef.value.push(el)
  }
}

function handleAddSpec() {
  attributesAddFormRef.value.open()
}

const spuForm = ref()

function onSubmit() {
  spuForm.value.validate(async (valid) => {
    try {
      if (valid && validateSku()) {
        // 深拷贝一份, 这样最终 server 端不满足，不需要影响原始数据
        const deepCopyFormData = cloneDeep(unref(form.value))
        deepCopyFormData.productSpecList = deepCopyFormData.skuList
        if (deepCopyFormData.productCategory && deepCopyFormData.productCategory.length) {
          deepCopyFormData.productCategory = deepCopyFormData.productCategory.at(-1)
        }
        delete deepCopyFormData.skuList
        // 校验都通过后提交表单
        let data = {
          ...deepCopyFormData,
          diyParams: {}
        }
        for (let i = 0; i < diyFieldList.value.length; i++) {
          const element = diyFieldList.value[i]
          data.diyParams[element.field] = data[element.field]
        }
        const id = route.query.id
        if (!id) {
          await ProductApi.createProduct(data)
          message.success(t('common.createSuccess'))
        } else {
          await ProductApi.updateProduct(data)
          message.success(t('common.updateSuccess'))
        }
      }
    } catch (error) {
      console.log(error)
    }
  })
}

// 作为活动组件的校验
const ruleConfig = [
  {
    name: 'specsName',
    rule: (arg) => arg.length,
    message: '规格名称不可为空 ！！！'
  },
  {
    name: 'price',
    rule: (arg) => arg >= 0.01,
    message: '商品销售价格必须大于等于 0.01 元！！！'
  }
]

/**
 * 保存时，每个商品规格的表单要校验下。例如说，销售金额最低是 0.01 这种。
 */
const validateSku = () => {
  let warningInfo = '请检查商品各行相关属性配置，'
  let validate = form.value.skuList.length > 0 // 默认通过
  if (!form.value.skuList.length) {
    message.info('请添加商品规格！！！')
  }
  for (const sku of form.value.skuList) {
    for (const rule of ruleConfig) {
      const arg = getValue(sku, rule.name)
      if (!rule.rule(arg)) {
        validate = false // 只要有一个不通过则直接不通过
        warningInfo += rule.message
        break
      }
    }
    // 只要有一个不通过则结束后续的校验
    if (!validate) {
      message.warning(warningInfo)
      throw new Error(warningInfo)
    }
  }
  return validate
}

const getValue = (obj, arg) => {
  const keys = arg.split('.')
  let value = obj
  for (const key of keys) {
    if (value && typeof value === 'object' && key in value) {
      value = value[key]
    } else {
      value = undefined
      break
    }
  }
  return value
}

const formLoading = ref(false)

/** 获得详情 */
const getDetail = async () => {
  if (route.query?.id) {
    formLoading.value = true
    try {
      const res = await ProductApi.getProduct(route.query.id)
      let diyField = {}
      if (res.diyParams) {
        diyField = isObject(res.diyParams) ? res.diyParams : JSON.parse(res.diyParams)
      }
      const propList = getPropertyList(res?.productSpecList || [])
      form.value = {
        ...res,
        ...diyField,
        skuList: res?.productSpecList || [],
        productSpecList: propList
      }
    } finally {
      formLoading.value = false
    }
  } else {
    form.value = {
      productName: undefined,
      productCategory: undefined,
      productBrand: undefined,
      productIntro: undefined,
      mainImage: 'https://ss-cloud.ahduima.com/1001/1796426117251600384.png',
      carouselImages: ['https://ss-cloud.ahduima.com/1001/1796426117251600384.png'],
      productSpecList: [],
      skuList: [],
      detailInfo: null,
      status: 0
    }
  }
}

/**
 * 获得商品的规格列表 - 商品相关的公共函数
 *
 * @param spu
 * @return PropertyAndValues 规格列表
 */
const getPropertyList = (list) => {
  //  直接拿返回的 skus 属性逆向生成出 propertyList
  const properties = []
  // 只有是多规格才处理
  list.forEach((sku) => {
    sku.properties?.forEach(({ propertyId, propertyName, valueId, valueName }) => {
      // 添加属性
      if (!properties?.some((item) => item.id === propertyId)) {
        properties.push({ id: propertyId, name: propertyName, values: [] })
      }
      // 添加属性值
      const index = properties?.findIndex((item) => item.id === propertyId)
      if (!properties[index].values?.some((value) => value.id === valueId)) {
        properties[index].values?.push({ id: valueId, name: valueName })
      }
    })
  })
  return properties
}

onMounted(async () => {
  getOptions()
  await getDetail()
})
</script>

<style lang="scss" scoped></style>
