<template>
  <ContentWrap>
    <el-form
      ref="queryFormRef"
      :inline="true"
      :model="queryParams"
      class="-mb-15px"
      label-width="88px"
    >
      <el-form-item label="工程名称" prop="projectName">
        <el-input
          v-model="queryParams.projectName"
          class="!w-240px"
          clearable
          placeholder="请输入工程名称"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="开始年度" prop="projectStartYear">
        <el-date-picker
          v-model="queryProjectStartYearValue"
          class="!w-180px"
          clearable
          placeholder="请选择年度"
          type="year"
          value-format="YYYY"
        />
      </el-form-item>
      <el-form-item>
        <el-button @click="handleQuery">
          <Icon class="mr-5px" icon="ep:search" />
          搜索
        </el-button>
        <el-button @click="resetQuery">
          <Icon class="mr-5px" icon="ep:refresh" />
          重置
        </el-button>
      </el-form-item>
    </el-form>
  </ContentWrap>

  <ContentWrap>
    <el-table
      ref="projectTableRef"
      v-loading="loading"
      :data="projectList"
      highlight-current-row
      @current-change="handleCurrentProjectChange"
    >
      <el-table-column align="center" label="项目ID" prop="id" width="88" />
      <el-table-column align="center" label="工程名称" min-width="220" prop="projectName" />
      <el-table-column align="center" label="项目经理" min-width="120" prop="projectManagerName" />
      <el-table-column
        align="center"
        label="项目负责人"
        min-width="120"
        prop="engineeringPrincipalName"
      />
      <el-table-column align="center" label="开始年度" prop="projectStartYear" width="120" />
    </el-table>
    <Pagination
      v-model:limit="queryParams.pageSize"
      v-model:page="queryParams.pageNo"
      :total="total"
      @pagination="getProjectList"
    />
  </ContentWrap>

  <el-row :gutter="16">
    <el-col :span="8">
      <ContentWrap>
        <div class="mb-12px text-14px font-600">
          {{ currentProject?.projectName || '合约规划列表' }}
        </div>
        <el-table
          ref="planningTableRef"
          v-loading="planningLoading"
          :data="planningList"
          highlight-current-row
          @current-change="handleCurrentPlanningChange"
        >
          <el-table-column align="center" label="规划内容" min-width="180" prop="planningContent" />
          <el-table-column align="center" label="归属类型" min-width="110">
            <template #default="scope">
              {{ getOwnershipTypeLabel(scope.row.ownershipType) }}
            </template>
          </el-table-column>
          <el-table-column align="center" label="开始年度" prop="planningStartYear" width="100" />
          <el-table-column align="center" label="考核产值(元)" width="120">
            <template #default="scope">
              {{ formatAmountText(scope.row.assessmentOutputValue) }}
            </template>
          </el-table-column>
        </el-table>
      </ContentWrap>
    </el-col>

    <el-col :span="16">
      <ContentWrap v-if="currentPlanning && currentGroup">
        <div class="mb-16px flex items-center justify-between gap-12px">
          <div class="text-16px font-600">{{ currentPlanning.planningContent }}</div>
          <div class="flex items-center gap-12px">
            <el-button
              v-hasPermi="['tjt:specialty-role-split:update']"
              plain
              type="primary"
              @click="openEditDialog"
            >
              <Icon class="mr-5px" icon="ep:edit" />
              编辑人员分配
            </el-button>
          </div>
        </div>

        <div class="mb-16px">
          <el-radio-group v-model="selectedGroupCode" size="small">
            <el-radio-button v-for="item in groupTabOptions" :key="item.value" :label="item.value">
              {{ item.label }}
            </el-radio-button>
          </el-radio-group>
        </div>

        <el-row :gutter="16" class="mb-16px">
          <el-col v-for="item in buildSummaryCards(currentGroup)" :key="item.label" :span="6">
            <div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
              <div class="text-12px text-[var(--el-text-color-secondary)]">{{ item.label }}</div>
              <div class="mt-6px text-18px font-600">{{ item.value }}</div>
            </div>
          </el-col>
        </el-row>

        <el-table :data="currentGroup.rows" border>
          <el-table-column align="center" label="角色" min-width="110" prop="roleName" />
          <el-table-column align="center" label="角色比例" min-width="120">
            <template #default="scope">
              {{ formatPercentText(scope.row.roleRatio) }}
            </template>
          </el-table-column>
          <el-table-column align="center" label="角色金额(元)" min-width="130">
            <template #default="scope">
              {{ formatAmountText(scope.row.roleAmount) }}
            </template>
          </el-table-column>
          <el-table-column align="center" label="人员合计" min-width="120">
            <template #default="scope">
              {{ formatPercentText(getPersonTotalRatio(scope.row)) }}
            </template>
          </el-table-column>
          <el-table-column align="center" label="人员信息" min-width="360">
            <template #default="scope">
              <div v-if="scope.row.persons?.length" class="person-display-list">
                <div
                  v-for="(person, index) in scope.row.persons"
                  :key="`${scope.row.specialtyCode}-${scope.row.roleCode}-display-${index}`"
                  class="person-display-row"
                >
                  <span class="person-display-name">{{ person.employeeName || '-' }}</span>
                  <span>{{ formatPercentText(person.personRatio) }}</span>
                  <span>{{ formatAmountText(person.personAmount) }} 元</span>
                </div>
              </div>
              <div v-else class="person-empty">暂无人员</div>
            </template>
          </el-table-column>
        </el-table>
      </ContentWrap>

      <ContentWrap v-else>
        <el-empty description="请选择合约规划后查看人员分配" />
      </ContentWrap>
    </el-col>
  </el-row>

  <Dialog v-model="dialogVisible" title="编辑专业人员角色分配" width="1180">
    <template v-if="currentEditGroup">
      <div class="mb-16px">
        <el-radio-group v-model="editGroupCode" size="small">
          <el-radio-button v-for="item in editGroupTabOptions" :key="item.value" :label="item.value">
            {{ item.label }}
          </el-radio-button>
        </el-radio-group>
      </div>

      <el-row :gutter="16" class="mb-16px">
        <el-col v-for="item in buildSummaryCards(currentEditGroup)" :key="item.label" :span="6">
          <div class="rounded-8px bg-[var(--el-fill-color-light)] px-16px py-12px">
            <div class="text-12px text-[var(--el-text-color-secondary)]">{{ item.label }}</div>
            <div class="mt-6px text-18px font-600">{{ item.value }}</div>
          </div>
        </el-col>
      </el-row>

      <el-table :data="currentEditGroup.rows" border>
        <el-table-column align="center" label="角色" min-width="110" prop="roleName" />
        <el-table-column align="center" label="角色比例" min-width="120">
          <template #default="scope">
            <el-input-number
              :model-value="toPercentValue(scope.row.roleRatio)"
              :disabled="isAutoCalculatedRole(scope.row)"
              :max="getRoleRatioMax(scope.row)"
              :min="0"
              :precision="2"
              :step="0.1"
              class="!w-1/1"
              controls-position="right"
              @update:model-value="(value) => updateRoleRatio(scope.row, value)"
            />
          </template>
        </el-table-column>
        <el-table-column align="center" label="角色金额(元)" min-width="130">
          <template #default="scope">
            {{ formatAmountText(scope.row.roleAmount) }}
          </template>
        </el-table-column>
        <el-table-column align="center" label="人员合计" min-width="120">
          <template #default="scope">
            <span :class="getPersonTotalClass(scope.row)">
              {{ formatPercentText(getPersonTotalRatio(scope.row)) }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="人员配置" min-width="520">
          <template #default="scope">
            <div class="person-editor">
              <div v-if="!scope.row.persons?.length" class="person-empty">
                {{
                  isProjectLeadRow(scope.row)
                    ? '暂无人员，请先到页面1维护项目经理或项目负责人'
                    : '暂无人员，请点击“添加人员”'
                }}
              </div>
              <div
                v-for="(person, index) in scope.row.persons"
                :key="`${scope.row.specialtyCode}-${scope.row.roleCode}-${index}`"
                class="person-row"
              >
                <el-input
                  v-if="isProjectLeadRow(scope.row)"
                  :model-value="person.employeeName || '-'"
                  class="!w-1/1"
                  disabled
                />
                <el-select
                  v-else
                  :model-value="person.employeeId"
                  class="!w-1/1"
                  clearable
                  filterable
                  remote
                  reserve-keyword
                  placeholder="请输入员工姓名搜索"
                  :remote-method="searchEmployees"
                  :loading="employeeLoading"
                  @change="(value) => handleEmployeeChange(person, value)"
                >
                  <el-option
                    v-for="employee in employeeOptions"
                    :key="employee.id"
                    :label="
                      employee.officeName
                        ? `${employee.employeeName} / ${employee.officeName}`
                        : employee.employeeName
                    "
                    :value="employee.id"
                  />
                </el-select>
                <el-input-number
                  :model-value="toPercentValue(person.personRatio)"
                  :max="getPersonRatioMax(scope.row, person)"
                  :min="0"
                  :precision="2"
                  :step="0.1"
                  class="!w-1/1"
                  controls-position="right"
                  @update:model-value="(value) => updatePersonRatio(scope.row, person, value)"
                />
                <div class="person-amount">{{ formatAmountText(person.personAmount) }} 元</div>
                <el-button
                  v-if="!isProjectLeadRow(scope.row)"
                  text
                  type="danger"
                  @click="removePerson(scope.row, index)"
                >
                  删除
                </el-button>
              </div>
              <div v-if="!isProjectLeadRow(scope.row)" class="person-toolbar">
                <el-button text type="primary" @click="addPerson(scope.row)">
                  <Icon class="mr-5px" icon="ep:plus" />
                  添加人员
                </el-button>
              </div>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </template>

    <template #footer>
      <el-button :loading="saveLoading" type="primary" @click="handleSave">保存</el-button>
      <el-button @click="dialogVisible = false">取消</el-button>
    </template>
  </Dialog>
</template>

<script lang="ts" setup>
import * as EmployeeApi from '@/api/tjt/employee'
import * as ProjectApi from '@/api/tjt/project'
import * as PlanningApi from '@/api/tjt/planning'
import * as SpecialtyRoleSplitApi from '@/api/tjt/specialtyRoleSplit'
import {
  formatAmountText,
  formatPercentText,
  fromPercentValue,
  getOwnershipTypeLabel,
  toPercentValue
} from '@/views/tjt/shared/planning'

defineOptions({ name: 'TjtStaffAssignment' })

const DESIGN_ROLE_CODE = 'design'
const PROJECT_LEAD_GROUP_CODE = 'project_lead'
const ROLE_PROJECT_MANAGER = 'project_manager'
const ROLE_ENGINEERING_PRINCIPAL = 'engineering_principal'
const EPSILON = 0.0001

type SpecialtyRolePersonVO = SpecialtyRoleSplitApi.SpecialtyRolePersonVO
type SpecialtyRoleSplitVO = SpecialtyRoleSplitApi.SpecialtyRoleSplitVO

interface SpecialtyGroup {
  specialtyCode: string
  specialtyName: string
  specialtyAmount: number
  rows: SpecialtyRoleSplitVO[]
  roleTotal: number
  personCount: number
}

const message = useMessage()

const loading = ref(false)
const planningLoading = ref(false)
const saveLoading = ref(false)
const total = ref(0)
const projectList = ref<ProjectApi.ProjectVO[]>([])
const planningList = ref<PlanningApi.ProjectPlanningVO[]>([])
const currentProject = ref<ProjectApi.ProjectVO>()
const currentPlanning = ref<PlanningApi.ProjectPlanningVO>()
const roleList = ref<SpecialtyRoleSplitVO[]>([])
const editRoleList = ref<SpecialtyRoleSplitVO[]>([])
const selectedGroupCode = ref('')
const editGroupCode = ref('')
const dialogVisible = ref(false)
const employeeOptions = ref<EmployeeApi.EmployeeSimpleVO[]>([])
const employeeLoading = ref(false)
const queryFormRef = ref()
const projectTableRef = ref()
const planningTableRef = ref()

const queryParams = reactive<ProjectApi.ProjectPageReqVO>({
  pageNo: 1,
  pageSize: 10,
  projectName: undefined,
  projectStartYear: undefined
})

const queryProjectStartYearValue = computed({
  get: () => (queryParams.projectStartYear ? String(queryParams.projectStartYear) : undefined),
  set: (value?: string) => {
    queryParams.projectStartYear = value ? Number(value) : undefined
  }
})

const roundRatio = (value?: number | string | null) => {
  const numericValue = Number(value || 0)
  return Number.isNaN(numericValue) ? 0 : Number(numericValue.toFixed(4))
}

const roundAmount = (value?: number | string | null) => {
  const numericValue = Number(value || 0)
  return Number.isNaN(numericValue) ? 0 : Number(numericValue.toFixed(2))
}

const multiplyAmount = (amount?: number | string | null, ratio?: number | string | null) =>
  roundAmount(Number(amount || 0) * Number(ratio || 0))

const normalizeEmployeeName = (value?: string) => value?.trim() || ''

const buildEditablePerson = (person?: SpecialtyRolePersonVO): SpecialtyRolePersonVO => ({
  employeeId: person?.employeeId,
  employeeName: person?.employeeName || '',
  personRatio:
    person?.personRatio === undefined || person?.personRatio === null
      ? undefined
      : roundRatio(person.personRatio),
  personAmount: roundAmount(person?.personAmount)
})

const buildEditableRow = (row: SpecialtyRoleSplitVO): SpecialtyRoleSplitVO => ({
  ...row,
  specialtyAmount: roundAmount(row.specialtyAmount),
  roleRatio: roundRatio(row.roleRatio),
  roleAmount: roundAmount(row.roleAmount),
  persons: (row.persons || []).map((person) => buildEditablePerson(person))
})

const cloneRoleRows = (rows: SpecialtyRoleSplitVO[]) => rows.map((item) => buildEditableRow(item))

const sumPersonRatios = (persons?: SpecialtyRolePersonVO[]) =>
  roundRatio((persons || []).reduce((sum, person) => sum + Number(person?.personRatio || 0), 0))

const getPersonTotalRatio = (row: SpecialtyRoleSplitVO) => sumPersonRatios(row.persons)

const getPersonTotalClass = (row: SpecialtyRoleSplitVO) =>
  getPersonTotalRatio(row) > 1 + EPSILON ? 'text-[var(--el-color-danger)]' : ''

const getPersonRatioMax = (row: SpecialtyRoleSplitVO, currentPerson: SpecialtyRolePersonVO) => {
  const otherTotalRatio = roundRatio(
    (row.persons || []).reduce((sum, person) => {
      if (person === currentPerson) {
        return sum
      }
      return sum + Number(person?.personRatio || 0)
    }, 0)
  )
  const currentPercent = toPercentValue(currentPerson.personRatio) ?? 0
  const remainPercent = toPercentValue(Math.max(0, 1 - otherTotalRatio)) ?? 0
  return Math.min(100, Math.max(currentPercent, remainPercent))
}

const countConfiguredPersons = (persons?: SpecialtyRolePersonVO[]) =>
  (persons || []).filter(
    (person) =>
      normalizeEmployeeName(person.employeeName) ||
      (person.personRatio !== undefined && person.personRatio !== null)
  ).length

const ensureEmployeeOptions = (persons?: SpecialtyRolePersonVO[]) => {
  const existingIds = new Set(employeeOptions.value.map((item) => item.id))
  ;(persons || []).forEach((person) => {
    if (!person.employeeId || existingIds.has(person.employeeId)) {
      return
    }
    employeeOptions.value.push({
      id: person.employeeId,
      employeeName: person.employeeName || '',
      officeId: undefined,
      officeName: undefined
    })
  })
}

const searchEmployees = async (keyword: string) => {
  employeeLoading.value = true
  try {
    employeeOptions.value = await EmployeeApi.getEmployeeSimpleList({
      keyword,
      status: '在职',
      enabledFlag: true
    })
    editRoleList.value.forEach((row) => ensureEmployeeOptions(row.persons))
  } finally {
    employeeLoading.value = false
  }
}

const handleEmployeeChange = (person: SpecialtyRolePersonVO, employeeId?: number) => {
  const employee = employeeOptions.value.find((item) => item.id === employeeId)
  person.employeeId = employeeId
  person.employeeName = employee?.employeeName || ''
}

const syncGroupRows = (source: SpecialtyRoleSplitVO[], specialtyCode: string) => {
  const rows = source.filter((item) => item.specialtyCode === specialtyCode)
  rows.forEach((row) => {
    row.persons = (row.persons || []).map((person) => buildEditablePerson(person))
    row.roleRatio = roundRatio(row.roleRatio)
    row.roleAmount = multiplyAmount(row.specialtyAmount, row.roleRatio)
    row.persons = (row.persons || []).map((person) => ({
      ...person,
      personAmount: multiplyAmount(row.roleAmount, person.personRatio)
    }))
  })
}

const syncAllDerivedValues = (source: SpecialtyRoleSplitVO[]) => {
  const specialtyCodeSet = new Set(source.map((item) => item.specialtyCode))
  specialtyCodeSet.forEach((specialtyCode) => syncGroupRows(source, specialtyCode))
}

const buildGroups = (source: SpecialtyRoleSplitVO[]): SpecialtyGroup[] => {
  const map = new Map<string, SpecialtyRoleSplitVO[]>()
  source.forEach((item) => {
    const list = map.get(item.specialtyCode) || []
    list.push(item)
    map.set(item.specialtyCode, list)
  })
  return Array.from(map.entries()).map(([specialtyCode, rows]) => {
    const sortedRows = [...rows].sort((a, b) => Number(a.sortNo || 0) - Number(b.sortNo || 0))
    return {
      specialtyCode,
      specialtyName: sortedRows[0]?.specialtyName || specialtyCode,
      specialtyAmount: roundAmount(sortedRows[0]?.specialtyAmount),
      rows: sortedRows,
      roleTotal: roundRatio(sortedRows.reduce((sum, item) => sum + Number(item.roleRatio || 0), 0)),
      personCount: sortedRows.reduce((sum, row) => sum + countConfiguredPersons(row.persons), 0)
    }
  })
}

const groups = computed(() => buildGroups(roleList.value))
const editGroups = computed(() => buildGroups(editRoleList.value))
const groupTabOptions = computed(() =>
  groups.value.map((item) => ({
    label: item.specialtyName,
    value: item.specialtyCode
  }))
)
const editGroupTabOptions = computed(() =>
  editGroups.value.map((item) => ({
    label: item.specialtyName,
    value: item.specialtyCode
  }))
)

const currentGroup = computed(
  () => groups.value.find((item) => item.specialtyCode === selectedGroupCode.value) || groups.value[0]
)
const currentEditGroup = computed(
  () =>
    editGroups.value.find((item) => item.specialtyCode === editGroupCode.value) || editGroups.value[0]
)
const isProjectLeadRow = (row?: SpecialtyRoleSplitVO) => row?.specialtyCode === PROJECT_LEAD_GROUP_CODE
const isEngineeringPrincipalRole = (row?: SpecialtyRoleSplitVO) =>
  row?.roleCode === ROLE_ENGINEERING_PRINCIPAL
const isDesignRole = (row?: SpecialtyRoleSplitVO) => row?.roleCode === DESIGN_ROLE_CODE
const isAutoCalculatedRole = (row?: SpecialtyRoleSplitVO) =>
  !!row &&
  (isProjectLeadRow(row) ? isEngineeringPrincipalRole(row) : isDesignRole(row))

const buildSummaryCards = (group?: SpecialtyGroup) => {
  if (!group) {
    return []
  }
  return [
    { label: '分组金额', value: `${formatAmountText(group.specialtyAmount)} 元` },
    { label: '角色合计', value: formatPercentText(group.roleTotal) },
    { label: '已配置人数', value: `${group.personCount} 人` },
    { label: '角色数', value: `${group.rows.length} 个` }
  ]
}

const ensureSelectedCode = (codes: string[], target: { value: string }) => {
  if (!codes.length) {
    target.value = ''
    return
  }
  if (!codes.includes(target.value)) {
    target.value = codes[0]
  }
}

const syncRoleRatiosForGroup = (source: SpecialtyRoleSplitVO[], specialtyCode: string) => {
  const rows = source.filter((item) => item.specialtyCode === specialtyCode)
  if (!rows.length) {
    return
  }
  if (specialtyCode === PROJECT_LEAD_GROUP_CODE) {
    const projectManagerRow = rows.find((item) => item.roleCode === ROLE_PROJECT_MANAGER)
    const engineeringPrincipalRow = rows.find((item) => item.roleCode === ROLE_ENGINEERING_PRINCIPAL)
    if (projectManagerRow && engineeringPrincipalRow) {
      projectManagerRow.roleRatio = roundRatio(projectManagerRow.roleRatio)
      engineeringPrincipalRow.roleRatio = roundRatio(
        Math.max(0, 1 - Number(projectManagerRow.roleRatio || 0))
      )
    }
    return
  }
  const designRow = rows.find((item) => item.roleCode === DESIGN_ROLE_CODE)
  if (!designRow) {
    return
  }
  const otherTotal = roundRatio(
    rows.reduce((sum, item) => {
      if (item.roleCode === DESIGN_ROLE_CODE) {
        return sum
      }
      return sum + Number(item.roleRatio || 0)
    }, 0)
  )
  designRow.roleRatio = roundRatio(Math.max(0, 1 - otherTotal))
}

const getRoleRatioMax = (row: SpecialtyRoleSplitVO) => {
  if (isAutoCalculatedRole(row)) {
    return 100
  }
  const rows = editRoleList.value.filter((item) => item.specialtyCode === row.specialtyCode)
  const otherEditableTotal = roundRatio(
    rows.reduce((sum, item) => {
      if (item === row || isAutoCalculatedRole(item)) {
        return sum
      }
      return sum + Number(item.roleRatio || 0)
    }, 0)
  )
  return toPercentValue(Math.max(0, 1 - otherEditableTotal)) ?? 100
}

watch(
  groups,
  (value) => {
    ensureSelectedCode(
      value.map((item) => item.specialtyCode),
      selectedGroupCode
    )
  },
  { immediate: true }
)

watch(
  editGroups,
  (value) => {
    ensureSelectedCode(
      value.map((item) => item.specialtyCode),
      editGroupCode
    )
  },
  { immediate: true }
)

const addPerson = (row: SpecialtyRoleSplitVO) => {
  if (isProjectLeadRow(row)) {
    return
  }
  if (!row.persons) {
    row.persons = []
  }
  row.persons.push(buildEditablePerson())
  syncGroupRows(editRoleList.value, row.specialtyCode)
}

const removePerson = (row: SpecialtyRoleSplitVO, index: number) => {
  if (isProjectLeadRow(row)) {
    return
  }
  row.persons?.splice(index, 1)
  syncGroupRows(editRoleList.value, row.specialtyCode)
}

const updatePersonRatio = (
  row: SpecialtyRoleSplitVO,
  person: SpecialtyRolePersonVO,
  value?: number
) => {
  const maxValue = getPersonRatioMax(row, person)
  const nextValue =
    value === undefined || value === null ? undefined : Math.min(Math.max(value, 0), maxValue)
  person.personRatio = fromPercentValue(nextValue) ?? undefined
  syncGroupRows(editRoleList.value, row.specialtyCode)
}

const updateRoleRatio = (row: SpecialtyRoleSplitVO, value?: number) => {
  const maxValue = getRoleRatioMax(row)
  const nextValue =
    value === undefined || value === null ? 0 : Math.min(Math.max(value, 0), maxValue)
  row.roleRatio = fromPercentValue(nextValue) ?? 0
  syncRoleRatiosForGroup(editRoleList.value, row.specialtyCode)
  syncGroupRows(editRoleList.value, row.specialtyCode)
}

const buildSavePersons = (
  row: SpecialtyRoleSplitVO
):
  | { persons: SpecialtyRolePersonVO[]; error?: never }
  | { persons?: never; error: string } => {
  const persons: SpecialtyRolePersonVO[] = []
  for (const person of row.persons || []) {
    const employeeName = normalizeEmployeeName(person.employeeName)
    const hasEmployeeId = !!person.employeeId
    const hasRatio = person.personRatio !== undefined && person.personRatio !== null
    if (!hasEmployeeId && !hasRatio) {
      continue
    }
    if (!hasEmployeeId || !hasRatio) {
      return { error: `${row.roleName} 的员工和比例必须同时填写` }
    }
    persons.push({
      employeeId: person.employeeId,
      employeeName: employeeName || undefined,
      personRatio: roundRatio(person.personRatio)
    })
  }
  return { persons }
}

const validateAndBuildSaveItems = () => {
  const items: SpecialtyRoleSplitApi.SpecialtyRoleSplitSaveItemVO[] = []
  for (const group of editGroups.value) {
    let roleTotal = 0
    for (const row of group.rows) {
      const result = buildSavePersons(row)
      if (result.error) {
        message.warning(result.error)
        return undefined
      }
      const persons = result.persons || []
      const personTotalRatio = sumPersonRatios(persons)
      if (personTotalRatio > 1 + EPSILON) {
        message.warning(`${group.specialtyName}-${row.roleName} 的人员比例合计不能大于 100%`)
        return undefined
      }
      if (
        row.roleCode === DESIGN_ROLE_CODE &&
        Number(row.roleAmount || 0) > EPSILON &&
        persons.length === 0
      ) {
        message.warning(`${group.specialtyName} 的设计角色金额大于 0 时必须配置人员`)
        return undefined
      }
      roleTotal = roundRatio(roleTotal + Number(row.roleRatio || 0))
      items.push({
        specialtyCode: row.specialtyCode,
        roleCode: row.roleCode,
        roleRatio: roundRatio(row.roleRatio),
        persons: isProjectLeadRow(row) ? [] : persons
      })
    }
    if (Math.abs(roleTotal - 1) > EPSILON) {
      message.warning(`${group.specialtyName} 的角色比例合计必须等于 100%`)
      return undefined
    }
  }
  return items
}

const getProjectList = async () => {
  loading.value = true
  try {
    const data = await ProjectApi.getProjectPage(queryParams)
    projectList.value = data.list
    total.value = data.total
    if (!projectList.value.length) {
      currentProject.value = undefined
      planningList.value = []
      currentPlanning.value = undefined
      roleList.value = []
      editRoleList.value = []
      return
    }
    const targetProjectId = currentProject.value?.id || projectList.value[0].id
    const targetProject =
      projectList.value.find((item) => item.id === targetProjectId) || projectList.value[0]
    await nextTick()
    projectTableRef.value?.setCurrentRow(targetProject)
  } finally {
    loading.value = false
  }
}

const getPlanningList = async () => {
  if (!currentProject.value?.id) {
    planningList.value = []
    currentPlanning.value = undefined
    roleList.value = []
    editRoleList.value = []
    return
  }
  planningLoading.value = true
  try {
    const list = await PlanningApi.getProjectPlanningListByProjectId(currentProject.value.id)
    planningList.value = list
    if (!planningList.value.length) {
      currentPlanning.value = undefined
      roleList.value = []
      editRoleList.value = []
      return
    }
    const targetPlanningId = currentPlanning.value?.id || planningList.value[0].id
    const targetPlanning =
      planningList.value.find((item) => item.id === targetPlanningId) || planningList.value[0]
    await nextTick()
    planningTableRef.value?.setCurrentRow(targetPlanning)
  } finally {
    planningLoading.value = false
  }
}

const loadRoleList = async (planningId: number) => {
  const data = await SpecialtyRoleSplitApi.getSpecialtyRoleSplitListByPlanningId(planningId)
  roleList.value = cloneRoleRows(data)
  roleList.value.forEach((row) => syncRoleRatiosForGroup(roleList.value, row.specialtyCode))
  syncAllDerivedValues(roleList.value)
}

const handleQuery = () => {
  queryParams.pageNo = 1
  getProjectList()
}

const resetQuery = () => {
  queryFormRef.value?.resetFields()
  handleQuery()
}

const handleCurrentProjectChange = async (row?: ProjectApi.ProjectVO) => {
  currentProject.value = row || undefined
  await getPlanningList()
}

const handleCurrentPlanningChange = async (row?: PlanningApi.ProjectPlanningVO) => {
  currentPlanning.value = row || undefined
  if (!row?.id) {
    roleList.value = []
    editRoleList.value = []
    return
  }
  await loadRoleList(row.id)
}

const openEditDialog = () => {
  if (!roleList.value.length) {
    return
  }
  editRoleList.value = cloneRoleRows(roleList.value)
  editRoleList.value.forEach((row) => syncRoleRatiosForGroup(editRoleList.value, row.specialtyCode))
  syncAllDerivedValues(editRoleList.value)
  editRoleList.value.forEach((row) => ensureEmployeeOptions(row.persons))
  editGroupCode.value = selectedGroupCode.value || editGroupTabOptions.value[0]?.value || ''
  dialogVisible.value = true
}

const handleSave = async () => {
  if (!currentPlanning.value?.id) {
    return
  }
  const items = validateAndBuildSaveItems()
  if (!items) {
    return
  }
  saveLoading.value = true
  try {
    await SpecialtyRoleSplitApi.saveSpecialtyRoleSplitBatch({
      planningId: currentPlanning.value.id,
      items
    })
    message.success('保存成功')
    dialogVisible.value = false
    await loadRoleList(currentPlanning.value.id)
  } finally {
    saveLoading.value = false
  }
}

onMounted(() => {
  getProjectList()
})

onActivated(() => {
  getProjectList()
})
</script>

<style lang="scss" scoped>
.person-empty {
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

.person-display-list,
.person-editor {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.person-display-row,
.person-row {
  display: grid;
  align-items: center;
  gap: 8px;
}

.person-display-row {
  grid-template-columns: minmax(120px, 1fr) 100px 120px;
  font-size: 13px;
}

.person-display-name {
  font-weight: 600;
}

.person-row {
  grid-template-columns: minmax(160px, 1fr) 180px 120px 64px;
}

.person-amount {
  color: var(--el-text-color-regular);
  text-align: right;
  white-space: nowrap;
}

.person-toolbar {
  display: flex;
  justify-content: flex-start;
}
</style>
