<template>
  <el-form
    ref="formRef"
    :model="formData"
    :rules="formRules"
    v-loading="formLoading"
    label-width="0px"
    :inline-message="true"
    :disabled="disabled"
  >
    <el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px">
      <el-table-column label="序号" type="index" align="center" width="60" />
      <el-table-column :label="productColumnLabel" min-width="180">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
            <el-input
              :model-value="getProductDisplayName(row)"
              readonly
              :clearable="!disabled"
              :placeholder="productPlaceholder"
              @click="handleProductInputClick(row)"
              @clear="handleProductClear(row)"
            />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="调出仓库" min-width="125">
        <template #default="{ row, $index }">
          <el-form-item
            :prop="`${$index}.fromWarehouseId`"
            :rules="formRules.fromWarehouseId"
            class="mb-0px!"
          >
            <el-select
              v-model="row.fromWarehouseId"
              clearable
              filterable
              :disabled="!row.productId"
              placeholder="请选择调出仓库"
              @change="onChangeFromWarehouse($event, row)"
            >
              <el-option
                v-for="item in getFromWarehouseOptions(row)"
                :key="getStockWarehouseId(item)"
                :label="getStockWarehouseName(item)"
                :value="getStockWarehouseId(item)"
              />
            </el-select>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="调出库区" min-width="125">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.fromAreaId`" :rules="formRules.fromAreaId" class="mb-0px!">
            <el-select
              v-model="row.fromAreaId"
              clearable
              filterable
              :disabled="!row.fromWarehouseId"
              placeholder="请选择调出库区"
              @change="handleFromAreaChange(row)"
            >
              <el-option
                v-for="item in getFromAreaOptions(row)"
                :key="getStockAreaId(item)"
                :label="getAreaLabel(item)"
                :value="getStockAreaId(item)"
              />
            </el-select>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="编码" min-width="150">
        <template #default="{ row }">
          <el-form-item class="mb-0px!">
            <el-input disabled v-model="row.productBarCode" />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="库存" min-width="100">
        <template #default="{ row }">
          <el-form-item class="mb-0px!">
            <el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="单位" min-width="80">
        <template #default="{ row }">
          <el-form-item class="mb-0px!">
            <el-input disabled v-model="row.productUnitName" />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="调入仓库" min-width="125">
        <template #default="{ row, $index }">
          <el-form-item
            :prop="`${$index}.toWarehouseId`"
            :rules="formRules.toWarehouseId"
            class="mb-0px!"
          >
            <el-select
              v-model="row.toWarehouseId"
              clearable
              filterable
              :disabled="!row.productId"
              placeholder="请选择调入仓库"
              @change="onChangeToWarehouse(row)"
            >
              <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
            </el-select>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="调入库区" min-width="125">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.toAreaId`" :rules="formRules.toAreaId" class="mb-0px!">
            <el-select
              v-model="row.toAreaId"
              clearable
              filterable
              :disabled="!row.toWarehouseId"
              placeholder="请选择调入库区"
              @change="handleToAreaChange(row)"
            >
              <el-option
                v-for="item in getToAreaOptions(row)"
                :key="item.id"
                :label="getAreaLabel(item)"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="数量" prop="count" fixed="right" min-width="140">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
            <el-input-number
              v-model="row.count"
              controls-position="right"
              :min="0.001"
              :precision="3"
              class="!w-100%"
            />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="备注" min-width="150">
        <template #default="{ row, $index }">
          <el-form-item :prop="`${$index}.remark`" class="mb-0px!">
            <el-input v-model="row.remark" placeholder="请输入备注" />
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column v-if="!disabled" align="center" fixed="right" label="操作" width="60">
        <template #default="{ $index }">
          <el-button type="danger" @click="handleDelete($index)" link>
            <Icon icon="ep:delete" />
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-form>
  <el-row justify="center" class="mt-3" v-if="!disabled">
    <el-button @click="handleAdd" round>+ 添加调拨产品</el-button>
  </el-row>

  <Dialog :title="productSelectTitle" v-model="productDialogVisible" width="900px" class="stock-move-product-dialog">
    <el-form :model="productQueryParams" :inline="true" class="-mb-15px">
      <el-form-item :label="t('ErpStock.Item.code')">
        <el-input
          v-model="productQueryParams.barCode"
          clearable
          :placeholder="t('ErpStock.Item.placeholderCode')"
          @keyup.enter="handleProductDialogQuery"
        />
      </el-form-item>
      <el-form-item :label="t('ErpStock.Item.name')">
        <el-input
          v-model="productQueryParams.name"
          clearable
          :placeholder="t('ErpStock.Item.placeholderName')"
          @keyup.enter="handleProductDialogQuery"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleProductDialogQuery">
          <Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
        </el-button>
      </el-form-item>
    </el-form>
    <el-table
      v-loading="productDialogLoading"
      :data="productDialogList"
      row-key="id"
      :stripe="true"
      :show-overflow-tooltip="true"
      @row-click="handleProductDialogRowClick"
    >
      <el-table-column width="55" align="center">
        <template #default="{ row }">
          <el-radio v-model="selectedProductId" :label="row.id">&nbsp;</el-radio>
        </template>
      </el-table-column>
      <el-table-column :label="t('ErpStock.Item.code')" prop="barCode" min-width="160" />
      <el-table-column :label="productColumnLabel" prop="name" min-width="160" />
      <el-table-column :label="t('ErpStock.Item.spec')" prop="standard" min-width="120" />
      <el-table-column :label="t('ErpStock.Item.category')" prop="subCategoryName" min-width="120" />
      <el-table-column :label="t('ErpStock.Item.unit')" prop="unitName" min-width="80" />
    </el-table>
    <div class="product-dialog-pagination">
      <Pagination
        :total="productDialogTotal"
        v-model:page="productQueryParams.pageNo"
        v-model:limit="productQueryParams.pageSize"
        @pagination="getProductDialogList"
      />
    </div>
    <template #footer>
      <el-button type="primary" :disabled="!selectedProductId" @click="confirmProductSelect">
        {{ t('common.ok') }}
      </el-button>
      <el-button @click="productDialogVisible = false">{{ t('common.cancel') }}</el-button>
    </template>
  </Dialog>
</template>
<script setup lang="ts">
import { ProductApi } from '@/api/erp/product/product'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
import { StockMoveApi } from '@/api/erp/stock/move'
import { erpCountInputFormatter, getSumValue } from '@/utils'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'

const { t } = useI18n()

const props = defineProps<{
  items?: any[]
  categoryType?: number
  disabled?: boolean
}>()

const formLoading = ref(false)
const formData = ref<any[]>([])
const sameAreaMessage = '调出库区和调入库区不能相同'
const formRules = reactive({
  inId: [{ required: true, message: '调度编号不能为空', trigger: 'submit' }],
  fromWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorFromWarehouseRequired'), trigger: 'submit' }],
  fromAreaId: [
    { required: true, message: t('ErpStock.Item.validatorAreaRequired'), trigger: 'submit' },
    { validator: validateDifferentArea, trigger: ['change', 'submit'] }
  ],
  toWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorToWarehouseRequired'), trigger: 'submit' }],
  toAreaId: [
    { required: true, message: t('ErpStock.Item.validatorAreaRequired'), trigger: 'submit' },
    { validator: validateDifferentArea, trigger: ['change', 'submit'] }
  ],
  productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'submit' }],
  count: [{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'submit' }]
})
const formRef = ref()
const warehouseList = ref<WarehouseVO[]>([])
const productList = ref<any[]>([])
const currentSelectRow = ref<any>()
const productDialogVisible = ref(false)
const productDialogLoading = ref(false)
const productDialogList = ref<any[]>([])
const productDialogTotal = ref(0)
const selectedProductId = ref<number>()
const productQueryParams = reactive({
  pageNo: 1,
  pageSize: 10,
  categoryType: undefined as number | undefined,
  barCode: undefined as string | undefined,
  name: undefined as string | undefined
})

const categoryTypeLabel = computed(() => {
  const option = getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE).find(
    (item) => Number(item.value) === Number(props.categoryType)
  )
  return option?.label || t('ErpStock.Item.productName')
})
const productColumnLabel = computed(() => categoryTypeLabel.value)
const productPlaceholder = computed(() => `请选择${productColumnLabel.value}`)
const productSelectTitle = computed(() => `选择${productColumnLabel.value}`)

watch(
  () => props.items,
  (val) => {
    formData.value = val || []
    ensureDefaultRow()
  },
  { immediate: true }
)

watch(
  () => props.categoryType,
  async (val, oldVal) => {
    await loadOptions()
    if (oldVal !== undefined && val !== oldVal) {
      formData.value.forEach(clearRowSelection)
    }
    ensureDefaultRow()
  },
  { immediate: true }
)

function getSummaries(param: SummaryMethodProps) {
  const { columns, data } = param
  const sums: string[] = []
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = t('common.total')
      return
    }
    if (column.property === 'count') {
      sums[index] = erpCountInputFormatter(getSumValue(data.map((item) => Number(item[column.property]))))
    } else {
      sums[index] = ''
    }
  })
  return sums
}

function ensureDefaultRow() {
  if (!props.disabled && formData.value.length === 0) {
    handleAdd()
  }
}

function handleAdd() {
  formData.value.push({
    id: undefined,
    fromWarehouseId: undefined,
    fromAreaId: undefined,
    toWarehouseId: undefined,
    toAreaId: undefined,
    toAreaList: [],
    productId: undefined,
    productName: undefined,
    productUnitName: undefined,
    productBarCode: undefined,
    stockCount: undefined,
    productStockList: [],
    count: 1,
    remark: undefined
  })
}

function handleDelete(index) {
  formData.value.splice(index, 1)
}

function isSameMoveArea(row) {
  return row.fromAreaId !== undefined && row.toAreaId !== undefined && String(row.fromAreaId) === String(row.toAreaId)
}

function validateDifferentArea(rule, _value, callback) {
  const rowIndex = Number(String(rule.field || '').split('.')[0])
  const row = formData.value[rowIndex]
  if (row && isSameMoveArea(row)) {
    callback(new Error(sameAreaMessage))
    return
  }
  callback()
}

function warnIfSameArea(row) {
  if (isSameMoveArea(row)) {
    ElMessage.warning(sameAreaMessage)
  }
}

function validateAreaFields(row) {
  const rowIndex = formData.value.indexOf(row)
  if (rowIndex < 0) return
  formRef.value?.validateField([`${rowIndex}.fromAreaId`, `${rowIndex}.toAreaId`])
}

async function handleFromAreaChange(row) {
  await setStockCount(row)
  warnIfSameArea(row)
  validateAreaFields(row)
}

function handleToAreaChange(row) {
  warnIfSameArea(row)
  validateAreaFields(row)
}

function onChangeFromWarehouse(_warehouseId, row) {
  const firstStock = getFromAreaOptions(row)[0]
  row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
  setStockCount(row)
  warnIfSameArea(row)
  validateAreaFields(row)
}

async function onChangeToWarehouse(row) {
  row.toAreaId = undefined
  row.toAreaList = []
  if (!row.toWarehouseId) return
  const warehouse = await WarehouseApi.getWarehouse(row.toWarehouseId)
  row.toAreaList = warehouse?.areaList || []
}

function handleProductInputClick(row) {
  if (props.disabled) return
  openProductSelectDialog(row)
}

function handleProductClear(row) {
  if (props.disabled) return
  clearRowSelection(row)
}

function getProductDisplayName(row) {
  return row.productName || productList.value.find((item) => item.id === row.productId)?.name || ''
}

async function openProductSelectDialog(row) {
  if (!props.categoryType) return
  currentSelectRow.value = row
  selectedProductId.value = row.productId
  productQueryParams.pageNo = 1
  productQueryParams.categoryType = props.categoryType
  productQueryParams.barCode = undefined
  productQueryParams.name = undefined
  productDialogVisible.value = true
  await getProductDialogList()
}

async function getProductDialogList() {
  productDialogLoading.value = true
  try {
    productQueryParams.categoryType = props.categoryType
    const data = await ProductApi.getProductPage(productQueryParams)
    productDialogList.value = data?.list || []
    productDialogTotal.value = data?.total || 0
  } finally {
    productDialogLoading.value = false
  }
}

function handleProductDialogQuery() {
  productQueryParams.pageNo = 1
  getProductDialogList()
}

function handleProductDialogRowClick(row: any) {
  selectedProductId.value = row.id
}

async function confirmProductSelect() {
  if (props.disabled) return
  const product = productDialogList.value.find((item) => item.id === selectedProductId.value)
  if (!product || !currentSelectRow.value) return
  fillRowByProduct(currentSelectRow.value, product)
  await loadProductStockList(currentSelectRow.value)
  productDialogVisible.value = false
}

function fillRowByProduct(row, product) {
  row.productId = product.id
  row.productName = product.name
  row.productUnitName = product.unitName
  row.productBarCode = product.barCode
  row.fromWarehouseId = undefined
  row.fromAreaId = undefined
  row.toWarehouseId = undefined
  row.toAreaId = undefined
  row.toAreaList = []
  row.stockCount = undefined
  row.productStockList = []
}

function clearRowSelection(row) {
  row.productId = undefined
  row.productName = undefined
  row.productUnitName = undefined
  row.productBarCode = undefined
  row.stockCount = undefined
  row.productStockList = []
  row.fromWarehouseId = undefined
  row.fromAreaId = undefined
  row.toWarehouseId = undefined
  row.toAreaId = undefined
  row.toAreaList = []
}

async function loadOptions() {
  const params = props.categoryType ? { categoryType: props.categoryType } : undefined
  formLoading.value = true
  try {
    const [products, warehouses] = await Promise.all([
      ProductApi.getProductSimpleList(params),
      WarehouseApi.getWarehouseSimpleList(params)
    ])
    productList.value = products || []
    warehouseList.value = warehouses || []
  } finally {
    formLoading.value = false
  }
}

function normalizeProductStockList(data) {
  if (Array.isArray(data)) return data
  if (Array.isArray(data?.list)) return data.list
  return []
}

async function loadProductStockList(row) {
  if (!row.productId) {
    row.productStockList = []
    return
  }
  const data = await StockMoveApi.getProductStockList(row.productId)
  row.productStockList = normalizeProductStockList(data)
  await fillProductStockAreaInfo(row.productStockList)
  const firstStock = row.productStockList[0]
  row.fromWarehouseId = firstStock ? getStockWarehouseId(firstStock) : undefined
  row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
  row.stockCount = firstStock ? getStockCount(firstStock) : undefined
}

async function fillProductStockAreaInfo(stockList) {
  const warehouseIds = Array.from(
    new Set((stockList || []).map((item) => getStockWarehouseId(item)).filter(Boolean))
  )
  await Promise.all(
    warehouseIds.map(async (warehouseId) => {
      const warehouse = await WarehouseApi.getWarehouse(warehouseId)
      const areaList = warehouse?.areaList || []
      stockList
        .filter((item) => Number(getStockWarehouseId(item)) === Number(warehouseId))
        .forEach((item) => {
          const area = areaList.find((areaItem) => Number(areaItem.id) === Number(getStockAreaId(item)))
          if (!area) return
          item.areaCode = area.areaCode
          item.areaName = area.areaName
        })
    })
  )
}

function getFromWarehouseOptions(row) {
  const stockList = row.productStockList || []
  const warehouseMap = new Map()
  stockList.forEach((item) => {
    const warehouseId = getStockWarehouseId(item)
    if (warehouseId !== undefined && !warehouseMap.has(warehouseId)) {
      warehouseMap.set(warehouseId, item)
    }
  })
  return Array.from(warehouseMap.values())
}

function getFromAreaOptions(row) {
  if (!row.fromWarehouseId) return []
  return (row.productStockList || []).filter(
    (item) => Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId)
  )
}

function getStockWarehouseId(stock) {
  return stock.warehouseId
}

function getStockWarehouseName(stock) {
  return stock.warehouseName || stock.name || stock.warehouseId
}

function getStockAreaId(stock) {
  return stock.areaId
}

function getStockCount(stock) {
  return stock.stockCount ?? stock.count
}


function getToAreaOptions(row) {
  if (Array.isArray(row.toAreaList) && row.toAreaList.length > 0) return row.toAreaList
  return warehouseList.value.find((item) => Number(item.id) === Number(row.toWarehouseId))?.areaList || []
}

function getAreaLabel(item) {
  const areaCode = item.areaCode || item.code
  const areaName = item.areaName || item.name
  return areaCode ? `${areaCode} - ${areaName || ''}` : areaName
}

async function setStockCount(row) {
  if (!row.productId || !row.fromWarehouseId || !row.fromAreaId) {
    row.stockCount = undefined
    return
  }
  if (!Array.isArray(row.productStockList) || row.productStockList.length === 0) {
    await loadProductStockList(row)
  }
  const stock = row.productStockList.find(
    (item) =>
      Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId) &&
      Number(getStockAreaId(item)) === Number(row.fromAreaId)
  )
  row.stockCount = stock ? getStockCount(stock) : 0
}

function validate() {
  return formRef.value.validate()
}
defineExpose({ validate })
</script>
<style scoped>
.stock-move-product-dialog :deep(.el-dialog__body) {
  padding-bottom: 8px;
}

.stock-move-product-dialog :deep(.el-dialog__footer) {
  border-top: 1px solid var(--el-border-color-lighter);
  padding-top: 16px;
}

.product-dialog-pagination {
  display: flex;
  justify-content: flex-end;
  width: 100%;
  margin-top: 16px;
  padding-bottom: 12px;
  overflow-x: auto;
}

.product-dialog-pagination :deep(.pagination-container) {
  margin: 0;
}
</style>
