<script lang="ts" setup>
import type { FormInstance, FormRules } from 'element-plus'
import type { DetailItem, ExtPropertyItem } from '../types'
import { OperationMeetingApi } from '@/api/pms/meeting'
import { useWindowSize } from '@vueuse/core'

interface Props {
  visible: boolean
  detail?: DetailItem
  type: 'create' | 'edit' | 'view'
  formType: 'create' | 'edit'
  extProperties?: ExtPropertyItem[]
}

interface ProjectNameSuggestion {
  value: string
}

const props = withDefaults(defineProps<Props>(), {
  detail: undefined
})

const emits = defineEmits<{
  'update:visible': [visible: boolean]
  save: [item: DetailItem]
}>()

const { width } = useWindowSize()
const detailFormRef = ref<FormInstance>()
const detailForm = ref<DetailItem>(createDetailItem())

const detailDrawerSize = computed(() => (width.value <= 768 ? '100%' : '50%'))
const isReadonly = computed(() => props.type === 'view')
const detailDrawerTitle = computed(() => {
  if (isReadonly.value) {
    return '查看会议明细'
  }

  return props.formType === 'create' ? '新增会议明细' : '编辑会议明细'
})

const projectNameOptions = ref<string[]>([])
const projectNameSuggestions = computed<ProjectNameSuggestion[]>(() =>
  projectNameOptions.value.map((item) => ({ value: item }))
)

const hasExtProperties = computed(() =>
  Boolean(props.extProperties?.length || detailForm.value.extProperty.length)
)
const currentPeriodExtProperties = computed(() =>
  hasExtProperties.value
    ? detailForm.value.extProperty.filter((item) => item.defaultValue !== 'next')
    : []
)
const nextPlanExtProperties = computed(() =>
  hasExtProperties.value
    ? detailForm.value.extProperty.filter((item) => item.defaultValue === 'next')
    : []
)

function createDetailItem(): DetailItem {
  return {
    raw: {},
    projectName: '',
    currentRevenue: undefined,
    cumulativeRevenue: undefined,
    beforeRevenue: undefined,
    currentOnAccount: undefined,
    cumulativeOnAccount: undefined,
    beforeOnAccount: undefined,
    currentPayment: undefined,
    cumulativePayment: undefined,
    beforePayment: undefined,
    plannedWorkload: '',
    actualCompletion: '',
    equipmentUtilizationRate: undefined,
    keyWorkCompletion: '',
    problemsAnalysis: '',
    qhse: '',
    nextPlannedWorkload: '',
    priorityTasks: '',
    extProperty: cloneExtProperties(props.extProperties)
  }
}

const cloneDetailItem = (data?: Partial<DetailItem>): DetailItem => ({
  raw: data?.raw || {},
  projectName: data?.projectName || '',
  currentRevenue: data?.currentRevenue,
  cumulativeRevenue: data?.cumulativeRevenue,
  beforeRevenue: data?.beforeRevenue,
  currentOnAccount: data?.currentOnAccount,
  cumulativeOnAccount: data?.cumulativeOnAccount,
  beforeOnAccount: data?.beforeOnAccount,
  currentPayment: data?.currentPayment,
  cumulativePayment: data?.cumulativePayment,
  beforePayment: data?.beforePayment,
  plannedWorkload: data?.plannedWorkload || '',
  actualCompletion: data?.actualCompletion || '',
  equipmentUtilizationRate: data?.equipmentUtilizationRate,
  keyWorkCompletion: data?.keyWorkCompletion || '',
  problemsAnalysis: data?.problemsAnalysis || '',
  qhse: data?.qhse || '',
  nextPlannedWorkload: data?.nextPlannedWorkload || '',
  priorityTasks: data?.priorityTasks || '',
  extProperty: mergeExtProperties(props.extProperties || [], data?.extProperty)
})

function normalizeTextValue(value: unknown) {
  return String(value ?? '').replace(/\\r\\n|\\n/g, '\n')
}

function parseNumberValue(value: unknown) {
  if (value === undefined || value === null || value === '') return undefined
  const parsed = Number(String(value).replace('%', ''))

  return Number.isNaN(parsed) ? undefined : parsed
}

function normalizeExtProperty(data?: Partial<ExtPropertyItem>): ExtPropertyItem {
  const dataType = normalizeTextValue(data?.dataType)

  return {
    name: normalizeTextValue(data?.name),
    identifier: normalizeTextValue(data?.identifier),
    dataType,
    required: data?.required ?? 0,
    unit: normalizeTextValue(data?.unit),
    accessMode: normalizeTextValue(data?.accessMode),
    defaultValue: normalizeTextValue(data?.defaultValue),
    maxValue: data?.maxValue,
    minValue: data?.minValue,
    sort: parseNumberValue(data?.sort),
    actualValue: dataType === 'double' ? parseNumberValue(data?.actualValue) : data?.actualValue,
    dropdownList: data?.dropdownList
  }
}

function parseExtPropertyList(data?: ExtPropertyItem[] | unknown): unknown[] {
  if (Array.isArray(data)) return data

  if (typeof data === 'string') {
    const text = data.trim()
    if (!text) return []

    try {
      return parseExtPropertyList(JSON.parse(text))
    } catch {
      return []
    }
  }

  if (data && typeof data === 'object') {
    const values = Object.values(data as Record<string, unknown>)

    return values.every((item) => item && typeof item === 'object') ? values : []
  }

  return []
}

function cloneExtProperties(data?: ExtPropertyItem[] | unknown): ExtPropertyItem[] {
  return parseExtPropertyList(data)
    .map((item) => normalizeExtProperty(item as Partial<ExtPropertyItem>))
    .filter((item) => item.identifier)
}

function mergeExtProperties(
  defaults: ExtPropertyItem[],
  current?: ExtPropertyItem[] | unknown
): ExtPropertyItem[] {
  const currentItems = cloneExtProperties(current)
  if (!defaults.length) return currentItems

  const currentMap = new Map(currentItems.map((item) => [item.identifier, item]))
  const defaultIdentifiers = new Set(defaults.map((item) => item.identifier))
  const mergedDefaults = defaults.map((item) => {
    const currentItem = currentMap.get(item.identifier)

    return {
      ...normalizeExtProperty(item),
      actualValue:
        currentItem && 'actualValue' in currentItem ? currentItem.actualValue : item.actualValue
    }
  })
  const extraItems = currentItems.filter((item) => !defaultIdentifiers.has(item.identifier))

  return [...mergedDefaults, ...extraItems].sort(
    (a, b) => Number(a.sort || 0) - Number(b.sort || 0)
  )
}

const requiredTextRule = (message: string) => [
  {
    required: true,
    whitespace: true,
    message,
    trigger: ['blur', 'change']
  }
]

const requiredNumberRule = (message: string) => [
  {
    required: true,
    type: 'number' as const,
    message,
    trigger: ['blur', 'change']
  }
]

const nonNegativeNumberRule = (requiredMessage: string, fieldLabel: string) => [
  ...requiredNumberRule(requiredMessage),
  {
    type: 'number' as const,
    min: 0,
    message: `${fieldLabel}不能小于0`,
    trigger: ['blur', 'change']
  }
]

const detailRules = reactive<FormRules>({
  projectName: requiredTextRule('请选择或者输入项目名称'),
  currentRevenue: nonNegativeNumberRule('请输入收入-本期', '收入-本期'),
  cumulativeRevenue: nonNegativeNumberRule('请输入收入-累计', '收入-累计'),
  currentOnAccount: nonNegativeNumberRule('请输入挂帐-本期', '挂帐-本期'),
  cumulativeOnAccount: nonNegativeNumberRule('请输入挂帐-累计', '挂帐-累计'),
  currentPayment: nonNegativeNumberRule('请输入回款-本期', '回款-本期'),
  cumulativePayment: nonNegativeNumberRule('请输入回款-累计', '回款-累计'),
  keyWorkCompletion: requiredTextRule('请输入重点工作及完成情况'),
  problemsAnalysis: requiredTextRule('请输入存在问题及分析'),
  qhse: requiredTextRule('请输入设备、安全管理工作'),
  nextPlannedWorkload: requiredTextRule('请输入下期计划工作量'),
  priorityTasks: requiredTextRule('请输入重点工作事项')
})

const isRequiredExtProperty = (item: ExtPropertyItem) =>
  item.required === true || item.required === 1 || item.required === '1'

const isDoubleExtProperty = (item: ExtPropertyItem) => item.dataType === 'double'

const normalizeExtPropertyKeyword = (value: unknown) =>
  String(value ?? '')
    .toLowerCase()
    .replace(/[\s%()（）]/g, '')

const getExtPropertySearchText = (item: ExtPropertyItem) =>
  `${normalizeExtPropertyKeyword(item.identifier)}${normalizeExtPropertyKeyword(item.name)}`

const isEquipmentUtilizationExtProperty = (item: ExtPropertyItem) => {
  const text = getExtPropertySearchText(item)

  return (
    text.includes('设备利用率') ||
    text.includes('equipmentutilization') ||
    text.includes('utilizationrate')
  )
}

const isConstructionEquipmentCountExtProperty = (item: ExtPropertyItem) => {
  const text = getExtPropertySearchText(item)

  return (
    text.includes('施工设备(台*天)') ||
    text.includes('施工设备') ||
    text.includes('constructionDeviceNum')
  )
}

const isOperatingEquipmentCountExtProperty = (item: ExtPropertyItem) => {
  const text = getExtPropertySearchText(item)

  return (
    text.includes('投运设备(台*天)') ||
    text.includes('投运设备') ||
    text.includes('inServiceDeviceNum')
  )
}

const equipmentUtilizationExtProperty = computed(() =>
  currentPeriodExtProperties.value.find(isEquipmentUtilizationExtProperty)
)

const constructionEquipmentCountExtProperty = computed(() =>
  currentPeriodExtProperties.value.find(isConstructionEquipmentCountExtProperty)
)

const operatingEquipmentCountExtProperty = computed(() =>
  currentPeriodExtProperties.value.find(isOperatingEquipmentCountExtProperty)
)

const updateEquipmentUtilizationExtProperty = () => {
  const utilizationItem = equipmentUtilizationExtProperty.value
  const constructionItem = constructionEquipmentCountExtProperty.value
  const operatingItem = operatingEquipmentCountExtProperty.value
  if (!utilizationItem || !constructionItem || !operatingItem) return

  const constructionCount = parseNumberValue(constructionItem.actualValue)
  const operatingCount = parseNumberValue(operatingItem.actualValue)

  if (constructionCount === undefined || operatingCount === undefined) {
    utilizationItem.actualValue = undefined
  } else if (operatingCount === 0) {
    utilizationItem.actualValue = 0
  } else {
    utilizationItem.actualValue = Number(((constructionCount / operatingCount) * 100).toFixed(2))
  }

  nextTick(() => detailFormRef.value?.clearValidate(getExtPropertyProp(utilizationItem)))
}

const hasExtPropertyActualValue = (item: ExtPropertyItem) => {
  const value = item.actualValue

  return typeof value === 'string' ? value.trim() !== '' : value !== undefined && value !== null
}

const getExtPropertyScope = (item: ExtPropertyItem) =>
  item.defaultValue === 'next' ? 'next' : 'current'

const getExtPropertyAlternativeGroupKey = (item: ExtPropertyItem) => {
  const value = String(item.maxValue ?? '').trim()

  if (!value || parseNumberValue(value) !== undefined) return ''

  return value
}

const getExtPropertyAlternativeGroups = (scope: string) => {
  const groups = new Map<string, ExtPropertyItem[]>()

  detailForm.value.extProperty.forEach((property) => {
    if (!isRequiredExtProperty(property) || getExtPropertyScope(property) !== scope) return

    const groupKey = getExtPropertyAlternativeGroupKey(property)
    if (!groupKey) return

    groups.set(groupKey, [...(groups.get(groupKey) || []), property])
  })

  return groups
}

const hasCompleteExtPropertyAlternativeGroup = (scope: string) =>
  Array.from(getExtPropertyAlternativeGroups(scope).values()).some((items) =>
    items.every(hasExtPropertyActualValue)
  )

const isAlternativeExtProperty = (item: ExtPropertyItem) => {
  if (!getExtPropertyAlternativeGroupKey(item)) return false

  return getExtPropertyAlternativeGroups(getExtPropertyScope(item)).size > 1
}

const getExtPropertyAlternativeProps = (item: ExtPropertyItem) =>
  Array.from(getExtPropertyAlternativeGroups(getExtPropertyScope(item)).values())
    .flat()
    .map((property) => getExtPropertyProp(property))

const handleExtPropertyValueChange = (item: ExtPropertyItem) => {
  updateEquipmentUtilizationExtProperty()

  if (
    !isAlternativeExtProperty(item) ||
    !hasCompleteExtPropertyAlternativeGroup(getExtPropertyScope(item))
  ) {
    return
  }

  nextTick(() => detailFormRef.value?.clearValidate(getExtPropertyAlternativeProps(item)))
}

const getExtPropertyLabel = (item: ExtPropertyItem) =>
  item.unit ? `${item.name}(${item.unit})` : item.name

const getExtPropertyProp = (item: ExtPropertyItem) => {
  const index = detailForm.value.extProperty.findIndex(
    (property) => property.identifier === item.identifier
  )

  return `extProperty.${Math.max(index, 0)}.actualValue`
}

const getExtPropertyRules = (item: ExtPropertyItem) => {
  if (!isRequiredExtProperty(item)) return []

  if (isAlternativeExtProperty(item)) {
    return [
      {
        validator: (_rule, _value, callback) => {
          if (hasCompleteExtPropertyAlternativeGroup(getExtPropertyScope(item))) {
            callback()
            return
          }

          callback(new Error('请至少完整填写一种工作量'))
        },
        trigger: ['blur', 'change']
      }
    ]
  }

  return isDoubleExtProperty(item)
    ? requiredNumberRule(`请输入${item.name}`)
    : requiredTextRule(`请输入${item.name}`)
}

const queryProjectNameSearch = (
  queryString: string,
  cb: (results: ProjectNameSuggestion[]) => void
) => {
  const keyword = queryString.trim().toLowerCase()

  if (!keyword) {
    cb(projectNameSuggestions.value)
    return
  }

  cb(projectNameSuggestions.value.filter((item) => item.value.toLowerCase().includes(keyword)))
}

watch(
  () =>
    [
      constructionEquipmentCountExtProperty.value?.actualValue,
      operatingEquipmentCountExtProperty.value?.actualValue,
      equipmentUtilizationExtProperty.value?.identifier
    ] as const,
  () => updateEquipmentUtilizationExtProperty(),
  { immediate: true }
)

const handleVisibleChange = (visible: boolean) => {
  emits('update:visible', visible)

  if (!visible) {
    detailForm.value = createDetailItem()
    nextTick(() => detailFormRef.value?.clearValidate())
  }
}

const saveDetailItem = async () => {
  if (isReadonly.value || !detailFormRef.value) return

  const valid = await detailFormRef.value.validate().catch(() => false)

  if (!valid) return

  emits('save', cloneDetailItem(detailForm.value))
}

async function loadProjectNameOptions() {
  try {
    const data = await OperationMeetingApi.getProjectNameOptions()
    projectNameOptions.value = Array.isArray(data) ? data.filter(Boolean).map(String) : []
  } catch {
    projectNameOptions.value = []
  }
}

watch(
  () => [props.visible, props.detail] as const,
  ([visible]) => {
    if (!visible) return

    detailForm.value = cloneDetailItem(props.detail)
    nextTick(() => detailFormRef.value?.clearValidate())
  },
  { immediate: true }
)

onMounted(() => {
  loadProjectNameOptions()
})
</script>

<template>
  <el-drawer
    :model-value="visible"
    @update:model-value="handleVisibleChange"
    :append-to-body="true"
    :size="detailDrawerSize"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :show-close="false"
    header-class="mb-0! p-4!"
    body-class="bg-gray-100"
    footer-class="p-4!">
    <template #header>
      <div class="flex items-center">
        <span class="font-bold text-xl">{{ detailDrawerTitle }}</span>
      </div>
    </template>

    <el-form
      ref="detailFormRef"
      label-position="top"
      size="default"
      :model="detailForm"
      :rules="detailRules"
      :disabled="isReadonly"
      scroll-to-error
      require-asterisk-position="right">
      <section class="detail-section">
        <div class="detail-section__grid detail-section__grid--single">
          <el-form-item label="项目名称" prop="projectName">
            <el-autocomplete
              v-model="detailForm.projectName"
              class="w-full!"
              placeholder="请选择或输入项目名称"
              clearable
              :fetch-suggestions="queryProjectNameSearch"
              :trigger-on-focus="true" />
          </el-form-item>
        </div>
      </section>

      <section class="detail-section">
        <h4 class="detail-section__title">经营情况(万元)</h4>
        <div class="detail-section__grid">
          <el-form-item label="收入-本期" prop="currentRevenue">
            <el-input-number
              v-model="detailForm.currentRevenue"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
          <el-form-item label="收入-累计" prop="cumulativeRevenue">
            <el-input-number
              v-model="detailForm.cumulativeRevenue"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
          <el-form-item label="挂帐-本期" prop="currentOnAccount">
            <el-input-number
              v-model="detailForm.currentOnAccount"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
          <el-form-item label="挂帐-累计" prop="cumulativeOnAccount">
            <el-input-number
              v-model="detailForm.cumulativeOnAccount"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
          <el-form-item label="回款-本期" prop="currentPayment">
            <el-input-number
              v-model="detailForm.currentPayment"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
          <el-form-item label="回款-累计" prop="cumulativePayment">
            <el-input-number
              v-model="detailForm.cumulativePayment"
              class="w-full!"
              :controls="false"
              :precision="2" />
          </el-form-item>
        </div>
      </section>

      <section v-if="currentPeriodExtProperties.length" class="detail-section">
        <h4 class="detail-section__title">本期生产运行情况</h4>
        <div class="detail-section__grid">
          <el-form-item
            v-for="item in currentPeriodExtProperties"
            :key="item.identifier"
            :label="getExtPropertyLabel(item)"
            :prop="getExtPropertyProp(item)"
            :rules="getExtPropertyRules(item)">
            <el-input-number
              v-if="isDoubleExtProperty(item)"
              v-model="item.actualValue as any"
              class="w-full!"
              :controls="false"
              :disabled="isReadonly || isEquipmentUtilizationExtProperty(item)"
              :precision="2"
              @change="handleExtPropertyValueChange(item)" />
            <el-input
              v-else
              v-model="item.actualValue"
              type="textarea"
              :rows="3"
              :disabled="isReadonly"
              :placeholder="`请输入${item.name}`"
              @input="handleExtPropertyValueChange(item)" />
          </el-form-item>
        </div>
      </section>

      <section class="detail-section">
        <h4 class="detail-section__title">生产管理情况及重点工作</h4>
        <div class="detail-section__grid">
          <el-form-item label="重点工作及完成情况" prop="keyWorkCompletion">
            <el-input
              v-model="detailForm.keyWorkCompletion"
              type="textarea"
              :rows="4"
              placeholder="请输入重点工作及完成情况" />
          </el-form-item>
          <el-form-item label="存在问题及分析" prop="problemsAnalysis">
            <el-input
              v-model="detailForm.problemsAnalysis"
              type="textarea"
              :rows="4"
              placeholder="请输入存在问题及分析" />
          </el-form-item>
        </div>
      </section>

      <section class="detail-section">
        <h4 class="detail-section__title">设备、安全管理工作</h4>
        <div class="detail-section__grid detail-section__grid--single">
          <el-form-item prop="qhse">
            <el-input
              v-model="detailForm.qhse"
              type="textarea"
              :rows="4"
              placeholder="请输入设备、安全管理工作" />
          </el-form-item>
        </div>
      </section>

      <section class="detail-section">
        <h4 class="detail-section__title">下期工作计划</h4>
        <div class="detail-section__grid">
          <el-form-item label="计划工作量" prop="nextPlannedWorkload">
            <el-input
              v-model="detailForm.nextPlannedWorkload"
              type="textarea"
              :rows="4"
              placeholder="请输入下期计划工作量" />
          </el-form-item>
          <el-form-item label="重点工作事项" prop="priorityTasks">
            <el-input
              v-model="detailForm.priorityTasks"
              type="textarea"
              :rows="4"
              placeholder="请输入重点工作事项" />
          </el-form-item>
          <el-form-item
            v-for="item in nextPlanExtProperties"
            :key="item.identifier"
            :label="getExtPropertyLabel(item)"
            :prop="getExtPropertyProp(item)"
            :rules="getExtPropertyRules(item)">
            <el-input-number
              v-if="isDoubleExtProperty(item)"
              v-model="item.actualValue as any"
              class="w-full!"
              :controls="false"
              :disabled="isReadonly"
              :precision="2"
              @change="handleExtPropertyValueChange(item)" />
            <el-input
              v-else
              v-model="item.actualValue"
              type="textarea"
              :rows="4"
              :disabled="isReadonly"
              :placeholder="`请输入${item.name}`"
              @input="handleExtPropertyValueChange(item)" />
          </el-form-item>
        </div>
      </section>
    </el-form>

    <template #footer>
      <el-button size="default" @click="handleVisibleChange(false)">取消</el-button>
      <el-button size="default" v-if="!isReadonly" type="primary" @click="saveDetailItem">
        保存
      </el-button>
    </template>
  </el-drawer>
</template>

<style scoped lang="scss">
.detail-section {
  padding: 20px;
  margin-bottom: 16px;
  background: #fff;
  border: 1px solid rgb(229 231 235 / 90%);
  border-radius: 12px;
}

.detail-section__title {
  margin: 0 0 16px;
  font-size: 16px;
  font-weight: 700;
  color: #1f2937;
}

.detail-section__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 24px;

  :deep(.el-form-item) {
    margin-bottom: 0;
  }
}

.detail-section__grid--single {
  grid-template-columns: 1fr;
}

@media (width <= 960px) {
  .detail-section__grid {
    grid-template-columns: 1fr;
  }
}
</style>
