import { useState, useMemo, useEffect } from 'react'
import { useSearchParams, useNavigate } from 'react-router-dom'
import { usePageSize } from '../hooks/usePageSize'
import { toast } from 'sonner'
import { toastError } from '../lib/errorToast'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useConfirm } from '../hooks/useConfirm'
import { Users, Plus, Check, UserX, UserPlus, DollarSign, Building2, RotateCcw, Upload, Download, Phone, MapPin, Search, Settings2, CheckCircle, FileText } from 'lucide-react'
import { rosterApi, employeeApi, terminationApi, workProcessApi, esignApi } from '../lib/api-services'
import api from '../lib/api'
import { copyToClipboard } from '../lib/clipboard'
import { useAuthStore } from '../store/authStore'
import { useDebouncedValue } from '../hooks/useDebouncedValue'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
import { Input, Label, Select } from '../components/ui/Input'
import Modal from '../components/ui/Modal'
import Pagination from '../components/ui/Pagination'
import { fmt, terminateReasonMap } from './roster/shared'
import PageGuide from '../components/ui/PageGuide'
import EmployeeProfile from './roster/EmployeeProfile'
import { InlineAlert } from '../components/ui/InlineAlert'
import { AddEmployeeModal, ResignModal, RehireModal, SalaryChangeModal, DeptChangeModal, ConfirmModal } from './roster/modals'
import SignMethodChoice from '../components/ui/SignMethodChoice'
import { ImportSettings } from './Settings'
import QueryError from '../components/ui/QueryError'

const ROSTER_COLUMNS = [
  { key: 'department', label: '部门' },
  { key: 'status', label: '状态' },
  { key: 'hireDate', label: '入职日期' },
  { key: 'position', label: '职务' },
  { key: 'phone', label: '手机号' },
  { key: 'gender', label: '性别' },
  { key: 'contractType', label: '合同类型' },
  { key: 'contractStatus', label: '合同状态' },
  { key: 'contractExpiry', label: '合同到期' },
  { key: 'socialStatus', label: '社保状态' },
  { key: 'socialInsBase', label: '社保基数' },
  { key: 'socialInsAmount', label: '社保缴费' },
  { key: 'records', label: '记录' },
] as const

const DEFAULT_VISIBLE = ['department', 'status', 'hireDate', 'position', 'phone', 'gender', 'contractType', 'contractStatus', 'contractExpiry', 'socialStatus']

function useRosterColumns() {
  const [visible, setVisible] = useState<string[]>(() => {
    try {
      const saved = localStorage.getItem('roster-columns')
      return saved ? JSON.parse(saved) : DEFAULT_VISIBLE
    } catch { return DEFAULT_VISIBLE }
  })
  const toggle = (key: string) => {
    setVisible(prev => {
      const next = prev.includes(key) ? prev.filter(k => k !== key) : [...prev, key]
      localStorage.setItem('roster-columns', JSON.stringify(next))
      return next
    })
  }
  const isVisible = (key: string) => visible.includes(key)
  return { isVisible, toggle, visible }
}

export default function Roster() {
  const queryClient = useQueryClient()
  const confirm = useConfirm()
  const [searchParams, setSearchParams] = useSearchParams()
  const navigate = useNavigate()
  const [selectedId, setSelectedId] = useState<string | null>(null)
  const [search, setSearch] = useState('')
  const debouncedSearch = useDebouncedValue(search, 300)
  const [showAddModal, setShowAddModal] = useState(false)
  const [showImportModal, setShowImportModal] = useState(false)
  const [showResignModal, setShowResignModal] = useState(false)
  const [resignEmployee, setResignEmployee] = useState<any>(null)
  const [showRehireModal, setShowRehireModal] = useState(false)
  const [rehireEmployee, setRehireEmployee] = useState<any>(null)
  const [showSalaryModal, setShowSalaryModal] = useState(false)
  const [salaryEmployee, setSalaryEmployee] = useState<any>(null)
  const [showDeptModal, setShowDeptModal] = useState(false)
  const [deptEmployee, setDeptEmployee] = useState<any>(null)
  const [showConfirmModal, setShowConfirmModal] = useState(false)
  const [confirmEmployee, setConfirmEmployee] = useState<any>(null)
  // 开具证明弹窗
  const [showCertModal, setShowCertModal] = useState(false)
  const [certEmployee, setCertEmployee] = useState<any>(null)
  const [certPurpose, setCertPurpose] = useState('')
  const [certType, setCertType] = useState('INCOME_CERT')
  // 续签合同弹窗
  const [showRenewModal, setShowRenewModal] = useState(false)
  const [renewEmployee, setRenewEmployee] = useState<any>(null)
  const [renewNewStartDate, setRenewNewStartDate] = useState('')
  const [renewNewEndDate, setRenewNewEndDate] = useState('')
  const [renewNewSalary, setRenewNewSalary] = useState('')
  const pageSize = usePageSize()
  const [page, setPage] = useState(1)
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
  const [showBatchRenewModal, setShowBatchRenewModal] = useState(false)
  // 签署方式选择弹窗
  const [signChoice, setSignChoice] = useState<{
    open: boolean
    employeeId: string
    employeeName: string
    employeeIdCardNumber?: string
    scene: 'CONTRACT' | 'RESIGNATION' | 'POLICY' | 'PAYSLIP' | 'ONBOARDING'
    documentTitle: string
    contractId?: string
    remark?: string
    actionName: string
  } | null>(null)
  const [batchRenewYears, setBatchRenewYears] = useState(3)
  const [previewData, setPreviewData] = useState<any>(null)
  const [filterStatus, setFilterStatus] = useState('')
  const [filterContractStatus, setFilterContractStatus] = useState('')
  const [filterDepartment, setFilterDepartment] = useState('')
  const [filterPosition, setFilterPosition] = useState('')
  const [showBatchTerminateModal, setShowBatchTerminateModal] = useState(false)
  const [batchTerminateDate, setBatchTerminateDate] = useState(() => new Date().toISOString().slice(0, 10))
  const [batchTerminateReason, setBatchTerminateReason] = useState('NEGOTIATED')
  const [terminatePreviewData, setTerminatePreviewData] = useState<any>(null)
  // 批量转正弹窗
  const [showBatchConfirmModal, setShowBatchConfirmModal] = useState(false)
  const [batchConfirmDate, setBatchConfirmDate] = useState(new Date().toISOString().slice(0, 10))
  const [batchConfirmSalary, setBatchConfirmSalary] = useState('')
  // 批量开具证明弹窗
  const [showBatchCertModal, setShowBatchCertModal] = useState(false)
  const [batchCertType, setBatchCertType] = useState('INCOME_CERT')

  const { data: rosterData, isLoading, isError, error, refetch } = useQuery<any>({
    queryKey: ['roster', page, pageSize, debouncedSearch, filterStatus, filterContractStatus, filterDepartment, filterPosition],
    queryFn: async () => {
      const params: any = { page, pageSize }
      if (debouncedSearch) params.search = debouncedSearch
      if (filterStatus && filterStatus !== 'PROBATION') params.status = filterStatus
      if (filterStatus === 'PROBATION') params.status = 'ACTIVE'
      if (filterContractStatus) params.contractStatus = filterContractStatus
      if (filterDepartment) params.department = filterDepartment
      if (filterPosition) params.position = filterPosition
      const res = await rosterApi.list({ search: debouncedSearch, page, pageSize, status: filterStatus === 'PROBATION' ? 'ACTIVE' : filterStatus || undefined, contractStatus: filterContractStatus || undefined, department: filterDepartment || undefined, position: filterPosition || undefined } as any) as any
      return res
    },
  })

  const employees = (rosterData?.data || []).filter((e: any) => {
    if (filterStatus === 'PROBATION') return e.probationInfo?.isProbation
    return true
  })
  const pagination = rosterData?.pagination || { page, pageSize, total: 0, totalPages: 0 }

  // 从 URL query 参数自动定位员工（从待办跳转或绩效/培训列表跳转时）
  const employeeParam = searchParams.get('employee')
  const employeeIdParam = searchParams.get('employeeId')
  useEffect(() => {
    // 优先按 employeeId 直接定位
    if (employeeIdParam && !selectedId) {
      setSelectedId(employeeIdParam)
      setSearchParams({}, { replace: true })
      return
    }
    if (!employeeParam) return
    setSearch(employeeParam)
    // 只有当 debouncedSearch 与参数一致时，搜索结果才真正匹配
    if (debouncedSearch === employeeParam && !isLoading && employees.length > 0 && !selectedId) {
      setSelectedId(employees[0].id)
      // 清除 URL 参数，避免后续搜索时重复触发
      setSearchParams({}, { replace: true })
    }
  }, [employeeParam, employeeIdParam, debouncedSearch, isLoading, employees, selectedId, setSearchParams])

  const addMutation = useMutation({
    mutationFn: async (data: any) => {
      const res = await employeeApi.create(data)
      return { res, data }
    },
    onSuccess: async ({ res, data }) => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      localStorage.removeItem('add-employee-draft')
      setShowAddModal(false)
      // 电子签：自动创建电子签署记录
      if (data.contract?.signMethod === 'ELECTRONIC' && res?.id) {
        try {
          // 查询员工档案获取刚创建的合同
          const profile = await rosterApi.profile(res.id) as any
          const contract = profile?.contracts?.[0]
          if (contract?.id) {
            await esignApi.create({
              contractId: contract.id,
              employeeId: res.id,
              documentTitle: `${data.name || ''}的劳动合同`,
              remark: '新增员工时自动发起',
              scene: 'CONTRACT',
            })
            toast.success('员工已添加，电子签署记录已创建')
          } else {
            toast.success('员工已添加，请前往员工档案发起电子签署')
          }
        } catch {
          toast.success('员工已添加，电子签署记录创建失败（可稍后手动发起）')
        }
      } else {
        toast.success('员工已添加，请前往员工档案签订合同')
      }
    },
    onError: (err: any) => toastError(err, '创建失败'),
  })

  const resignMutation = useMutation({
    mutationFn: (data: any) => terminationApi.createDraft({
      employeeId: data.employeeId,
      type: 'RESIGNATION',
      reason: 'RESIGNATION',
      terminationDate: data.terminationDate,
      resignationReason: data.resignationReason,
      remark: data.remark,
    }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      queryClient.invalidateQueries({ queryKey: ['esign-records'] })
      toast.success('已创建离职草稿，离职协议电子签署已自动发起', {
        action: { label: '查看签署', onClick: () => navigate('/esign') },
      })
      setShowResignModal(false)
      setResignEmployee(null)
    },
  })

  const revokeMutation = useMutation({
    mutationFn: (recordId: string) => terminationApi.revoke(recordId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
    },
  })

  const rehireMutation = useMutation({
    mutationFn: async (data: any) => {
      const res = await employeeApi.rehire(rehireEmployee?.id, data)
      return { res, data }
    },
    onSuccess: async ({ res, data }) => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      setShowRehireModal(false)
      // 电子签：自动创建电子签署记录
      if (data.contract?.signMethod === 'ELECTRONIC' && rehireEmployee?.id) {
        try {
          const profile = await rosterApi.profile(rehireEmployee.id) as any
          const contract = profile?.contracts?.[0]
          if (contract?.id) {
            await esignApi.create({
              contractId: contract.id,
              employeeId: rehireEmployee.id,
              documentTitle: `${rehireEmployee?.name || ''}的劳动合同`,
              remark: '重新入职时自动发起',
              scene: 'CONTRACT',
            })
            toast.success('重新入职成功，电子签署记录已创建')
          } else {
            toast.success('重新入职成功，请前往员工档案发起电子签署')
          }
        } catch {
          toast.success('重新入职成功，电子签署记录创建失败（可稍后手动发起）')
        }
      } else {
        toast.success('重新入职成功，请前往员工档案签订合同')
      }
      setRehireEmployee(null)
    },
  })

  const salaryChangeMutation = useMutation({
    mutationFn: (data: any) => rosterApi.salaryChange(salaryEmployee?.id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      setShowSalaryModal(false)
      // 弹出签署方式选择
      setSignChoice({
        open: true,
        employeeId: salaryEmployee?.id || '',
        employeeName: salaryEmployee?.name || '',
        employeeIdCardNumber: salaryEmployee?.idCardNumber,
        scene: 'POLICY',
        documentTitle: `${salaryEmployee?.name || ''}的薪酬调整确认书`,
        remark: '薪酬变更时发起',
        actionName: '薪酬变更',
      })
      setSalaryEmployee(null)
    },
  })

  const deptChangeMutation = useMutation({
    mutationFn: (data: any) => rosterApi.departmentChange(deptEmployee?.id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      setShowDeptModal(false)
      // 弹出签署方式选择
      setSignChoice({
        open: true,
        employeeId: deptEmployee?.id || '',
        employeeName: deptEmployee?.name || '',
        employeeIdCardNumber: deptEmployee?.idCardNumber,
        scene: 'POLICY',
        documentTitle: `${deptEmployee?.name || ''}的调岗确认书`,
        remark: '部门/岗位调动时发起',
        actionName: '调岗调动',
      })
      setDeptEmployee(null)
    },
  })

  // 转正 mutation
  const confirmMutation = useMutation({
    mutationFn: (data: { employeeId: string; confirmDate: string; regularSalary?: number }) =>
      workProcessApi.create({ type: 'CONFIRM', title: '转正', employeeId: data.employeeId, formData: { employeeId: data.employeeId, confirmDate: data.confirmDate, regularSalary: data.regularSalary }, status: 'DRAFT' }),
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      setShowConfirmModal(false)
      const originalSalary = confirmEmployee?.monthlySalary ? Number(confirmEmployee.monthlySalary) : null
      const newSalary = variables.regularSalary
      // 薪资有变化时弹出签署方式选择
      if (newSalary && newSalary !== originalSalary) {
        setSignChoice({
          open: true,
          employeeId: variables.employeeId,
          employeeName: confirmEmployee?.name || '',
          employeeIdCardNumber: confirmEmployee?.idCardNumber,
          scene: 'POLICY',
          documentTitle: `${confirmEmployee?.name || ''}的转正薪酬调整确认书`,
          remark: `转正薪资调整：¥${originalSalary || 0} → ¥${newSalary}`,
          actionName: '转正调薪',
        })
      } else {
        toast.success('转正已提交')
      }
      setConfirmEmployee(null)
    },
    onError: (err: any) => toast.error(err?.response?.data?.error?.message || '转正失败'),
  })

  const batchRenewMutation = useMutation({
    mutationFn: (data: { contractIds: string[]; years: number }) => employeeApi.batchRenew(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      setShowBatchRenewModal(false)
      setSelectedIds(new Set())
      setPreviewData(null)
    },
  })

  const previewRenewMutation = useMutation({
    mutationFn: (contractIds: string[]) => employeeApi.previewRenew(contractIds),
    onSuccess: (data: any) => {
      setPreviewData(data.data)
    },
  })

  const previewTerminateMutation = useMutation({
    mutationFn: (items: Array<{ employeeId: string; reason: string; terminationDate: string }>) =>
      terminationApi.batchPreview(items),
    onSuccess: (data: any) => {
      setTerminatePreviewData(data.data)
    },
  })

  const batchTerminateMutation = useMutation({
    mutationFn: async (items: Array<{ employeeId: string; reason: string; terminationDate: string }>) => {
      const results = await Promise.all(
        items.map(item => terminationApi.createDraft({
          employeeId: item.employeeId,
          type: 'TERMINATION',
          reason: item.reason,
          terminationDate: item.terminationDate,
        }).catch((err: any) => ({ error: err, employeeId: item.employeeId })))
      )
      return results
    },
    onSuccess: (results: any) => {
      const success = results.filter((r: any) => !r?.error).length
      const failed = results.filter((r: any) => r?.error).length
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      queryClient.invalidateQueries({ queryKey: ['dashboard'] })
      queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
      queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
      if (success > 0) toast.success(`已创建 ${success} 个解聘草稿，请前往「解聘补偿」页面完成流程`)
      if (failed > 0) toast.error(`${failed} 个员工创建草稿失败`)
      setShowBatchTerminateModal(false)
      setTerminatePreviewData(null)
      setSelectedIds(new Set())
    },
  })

  /** 开具证明：直接创建并提交工单 */
  const certMutation = useMutation({
    mutationFn: async (data: { employeeId: string; formData: Record<string, unknown> }) => {
      const certTitleMap: Record<string, string> = {
        INCOME_CERT: '开具收入证明',
        EMPLOYMENT_CERT: '开具在职证明',
        LEAVING_CERT: '开具离职证明',
      }
      const created: any = await workProcessApi.create({ type: certType, title: certTitleMap[certType] || '开具证明', employeeId: data.employeeId, formData: data.formData, status: 'DRAFT' })
      if (created?.id) {
        await workProcessApi.submit(created.id)
      }
      return created
    },
    onSuccess: () => {
      toast.success('证明已开具，可在「证据管理」中查看和下载')
      queryClient.invalidateQueries({ queryKey: ['work-processes'] })
      setShowCertModal(false)
      setCertEmployee(null)
      setCertPurpose('')
    },
    onError: (err: any) => toastError(err, '开具证明失败'),
  })

  /** 续签合同：直接创建并提交工单 */
  const renewMutation = useMutation({
    mutationFn: async (data: { employeeId: string; formData: Record<string, unknown> }) => {
      const created: any = await workProcessApi.create({ type: 'RENEW', title: '合同续签', employeeId: data.employeeId, formData: data.formData, status: 'DRAFT' })
      if (created?.id) {
        await workProcessApi.submit(created.id)
      }
      return created
    },
    onSuccess: () => {
      toast.success('合同续签已完成')
      queryClient.invalidateQueries({ queryKey: ['work-processes'] })
      queryClient.invalidateQueries({ queryKey: ['roster'] })
      setShowRenewModal(false)
      // 弹出签署方式选择
      setSignChoice({
        open: true,
        employeeId: renewEmployee?.id || '',
        employeeName: renewEmployee?.name || '',
        employeeIdCardNumber: renewEmployee?.idCardNumber,
        scene: 'CONTRACT',
        documentTitle: `${renewEmployee?.name || ''}的续签劳动合同`,
        remark: '合同续签时发起',
        actionName: '合同续签',
      })
      setRenewEmployee(null)
      setRenewNewStartDate('')
      setRenewNewEndDate('')
      setRenewNewSalary('')
    },
    onError: (err: any) => toastError(err, '续签合同失败'),
  })

  /** 批量转正：为选中的试用期员工创建转正草稿 */
  const handleBatchConfirm = async () => {
    const probationEmployees = employees.filter((e: any) => selectedIds.has(e.id) && e.probationInfo?.isProbation)
    if (probationEmployees.length === 0) {
      toast.error('选中的员工中没有试用期员工')
      return
    }
    const confirmDate = batchConfirmDate
    let success = 0
    let failed = 0
    await Promise.all(
      probationEmployees.map(async (emp: any) => {
        try {
          await workProcessApi.create({
            type: 'CONFIRM',
            title: '批量转正',
            employeeId: emp.id,
            formData: { employeeId: emp.id, confirmDate, salary: batchConfirmSalary || undefined },
            status: 'DRAFT',
          })
          success++
        } catch {
          failed++
        }
      })
    )
    queryClient.invalidateQueries({ queryKey: ['roster'] })
    queryClient.invalidateQueries({ queryKey: ['dashboard'] })
    if (success > 0) toast.success(`已为 ${success} 名员工创建转正草稿`)
    if (failed > 0) toast.error(`${failed} 名员工转正失败`)
    setSelectedIds(new Set())
    setShowBatchConfirmModal(false)
  }

  /** 批量开具证明：直接为选中员工创建并提交证明 */
  const handleBatchCert = async () => {
    if (selectedIds.size === 0) {
      toast.error('请至少选择一名员工')
      return
    }
    const certTitleMap: Record<string, string> = {
      INCOME_CERT: '开具收入证明',
      EMPLOYMENT_CERT: '开具在职证明',
      LEAVING_CERT: '开具离职证明',
    }
    let success = 0
    let failed = 0
    for (const id of selectedIds) {
      const emp = employees.find((e: any) => e.id === id)
      if (!emp) continue
      try {
        const created: any = await workProcessApi.create({
          type: batchCertType,
          title: certTitleMap[batchCertType] || '开具证明',
          employeeId: id,
          formData: {
            employeeId: id,
            employeeName: emp.name,
            idCardNumber: emp.idCardNumber || '',
            position: emp.position || '',
            monthlyIncome: emp.monthlySalary ? `¥${emp.monthlySalary}` : '',
            purpose: '批量开具',
          },
          status: 'DRAFT',
        })
        if (created?.id) {
          await workProcessApi.submit(created.id)
        }
        success++
      } catch {
        failed++
      }
    }
    queryClient.invalidateQueries({ queryKey: ['work-processes'] })
    if (success > 0) toast.success(`已为 ${success} 名员工开具证明`)
    if (failed > 0) toast.error(`${failed} 名员工开具证明失败`)
    setSelectedIds(new Set())
    setShowBatchCertModal(false)
  }

  const toggleSelect = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev)
      if (next.has(id)) next.delete(id)
      else next.add(id)
      return next
    })
  }

  const toggleSelectAll = () => {
    if (selectedIds.size === employees.length) {
      setSelectedIds(new Set())
    } else {
      setSelectedIds(new Set(employees.map((e: any) => e.id)))
    }
  }

  const clearFilters = () => {
    setSearch('')
    setFilterStatus('')
    setFilterContractStatus('')
    setFilterDepartment('')
    setFilterPosition('')
    setPage(1)
  }

  const hasActiveFilters = search || filterStatus || filterContractStatus || filterDepartment || filterPosition

  /** 全局合同风险统计（来自后端，与风险中心同口径） */
  const globalRiskStats = rosterData?.globalRiskStats
  const riskStats = useMemo(() => {
    if (globalRiskStats) return globalRiskStats
    // fallback: 当前页统计
    const expiring = employees.filter((e: any) => e.contractStatus === 'expiring').length
    const expired = employees.filter((e: any) => e.contractStatus === 'expired').length
    const unsigned = employees.filter((e: any) => ['unsigned', 'unsigned_over_30', 'unsigned_over_year'].includes(e.contractStatus)).length
    const probation = employees.filter((e: any) => e.probationInfo?.isProbation && e.probationInfo?.isExpiring).length
    return { expiring, expired, unsigned, probation }
  }, [globalRiskStats, employees])

  /** 快捷筛选标签 */
  const quickFilters = [
    { key: 'expiring', label: '即将到期', count: riskStats.expiring, color: 'amber', filter: { status: '', contractStatus: 'expiring', department: '' } },
    { key: 'expired', label: '已到期', count: riskStats.expired, color: 'rose', filter: { status: '', contractStatus: 'expired', department: '' } },
    { key: 'unsigned', label: '未签合同', count: riskStats.unsigned, color: 'rose', filter: { status: '', contractStatus: 'unsigned', department: '' } },
    { key: 'probation', label: '试用期即将到期', count: riskStats.probation, color: 'amber', filter: { status: 'PROBATION', contractStatus: '', department: '' } },
  ].filter(f => f.count > 0)

  const { data: departmentList } = useQuery<string[]>({
    queryKey: ['roster-departments'],
    queryFn: async () => {
      return await rosterApi.departments()
    },
  })

  const { data: positionList } = useQuery<string[]>({
    queryKey: ['roster-positions'],
    queryFn: async () => {
      const res = await api.get('/roster/positions')
      return res.data as string[]
    },
  })

  const { isVisible: colVisible, toggle: colToggle } = useRosterColumns()
  const [showColSettings, setShowColSettings] = useState(false)

  const filtered = employees?.filter((e: any) =>
    !search || e.name.includes(search) || e.department.includes(search) || (e.idCardNumber && e.idCardNumber.includes(search))
  ) || []

  // 通讯录视图数据
  if (selectedId) {
    return <EmployeeProfile employeeId={selectedId} onBack={() => setSelectedId(null)} />
  }

  return (
    <div className="space-y-5">
      <PageGuide>
        员工花名册统一管理所有员工档案信息，包括基本信息、合同、薪酬、社保等。支持搜索、筛选、导出。点击员工可查看详细档案。支持入职登记、离职办理、合同签订等操作。关联：入职后请前往「用工办理」签订合同；合同到期请前往「风险中心」处理；离职请前往「离职管理」计算补偿。
      </PageGuide>
      <div className="flex flex-col gap-4 xl:flex-row xl:items-end xl:justify-between">
        <div>
          <div className="flex items-center gap-2">
            <Users className="h-5 w-5 text-primary" />
            <h1 className="text-base font-semibold">员工花名册</h1>
          </div>
          <p className="mt-1 text-sm text-gray-500 whitespace-nowrap">统一查看员工状态、合同风险及人事档案</p>
        </div>
        <div className="flex flex-wrap items-center justify-start gap-2 xl:justify-end">
          <Input
            placeholder="搜索姓名、部门或身份证后4位"
            value={search}
            onChange={(e) => { setSearch(e.target.value); setPage(1) }}
            className="!w-full sm:!w-64 shrink-0"
          />
          <select
            value={filterStatus}
            onChange={(e) => { setFilterStatus(e.target.value); setPage(1) }}
            className="h-9 rounded-md border border-gray-200 bg-white px-3 text-sm text-gray-700 shadow-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
          >
            <option value="">全部状态</option>
            <option value="ACTIVE">在职</option>
            <option value="PROBATION">试用期</option>
            <option value="PRE_HIRE">预入职</option>
            <option value="RESIGNED">离职</option>
          </select>
          <select
            value={filterContractStatus}
            onChange={(e) => { setFilterContractStatus(e.target.value); setPage(1) }}
            className="h-9 rounded-md border border-gray-200 bg-white px-3 text-sm text-gray-700 shadow-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
          >
            <option value="">全部合同</option>
            <option value="active">正常</option>
            <option value="expiring">即将到期</option>
            <option value="expired">已到期</option>
            <option value="unsigned">未签合同</option>
            <option value="unsigned_over_30">未签合同(超30天)</option>
            <option value="unsigned_over_year">未签合同(已满一年)</option>
          </select>
          <select
            value={filterDepartment}
            onChange={(e) => { setFilterDepartment(e.target.value); setPage(1) }}
            className="h-9 rounded-md border border-gray-200 bg-white px-3 text-sm text-gray-700 shadow-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
          >
            <option value="">全部部门</option>
            {departmentList?.map((d: string) => <option key={d} value={d}>{d}</option>)}
          </select>
          <select
            value={filterPosition}
            onChange={(e) => { setFilterPosition(e.target.value); setPage(1) }}
            className="h-9 rounded-md border border-gray-200 bg-white px-3 text-sm text-gray-700 shadow-sm outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/10"
          >
            <option value="">全部职务</option>
            {positionList?.map((p: string) => <option key={p} value={p}>{p}</option>)}
          </select>
          {hasActiveFilters && (
            <button onClick={clearFilters} className="h-9 px-2 text-sm text-gray-400 transition hover:text-gray-700">清除筛选</button>
          )}
          <Button onClick={() => setShowAddModal(true)} className="h-9 shrink-0">
            <Plus className="mr-1.5 h-4 w-4" />添加员工
          </Button>
          <Button variant="secondary" onClick={() => setShowImportModal(true)} className="h-9 shrink-0">
            <Upload className="mr-1.5 h-4 w-4" />批量导入
          </Button>
          <Button variant="secondary" onClick={async () => {
            try {
              const params = new URLSearchParams()
              if (debouncedSearch) params.set('search', debouncedSearch)
              if (filterStatus) params.set('status', filterStatus)
              if (filterDepartment) params.set('department', filterDepartment)
              if (filterPosition) params.set('position', filterPosition)
              if (filterContractStatus) params.set('contractStatus', filterContractStatus)
              const token = useAuthStore.getState().accessToken
              const baseURL = import.meta.env.DEV ? 'http://localhost:3000/api/v1' : '/api/v1'
              const res = await fetch(`${baseURL}/export/roster?${params}`, { headers: { Authorization: `Bearer ${token}` } })
              if (!res.ok) throw new Error('导出失败')
              const blob = await res.blob()
              const url = URL.createObjectURL(blob)
              const a = document.createElement('a')
              a.href = url
              a.download = `花名册-${new Date().toISOString().slice(0, 10)}.xlsx`
              a.click()
              URL.revokeObjectURL(url)
            } catch { toast.error('导出失败') }
          }} className="h-9 shrink-0">
            <Download className="mr-1.5 h-4 w-4" />导出
          </Button>
          <div className="relative shrink-0">
            <Button variant="secondary" onClick={() => setShowColSettings(v => !v)} className="h-9">
              <Settings2 className="mr-1.5 h-4 w-4" />列设置
            </Button>
            {showColSettings && (
              <>
                <div className="fixed inset-0 z-10" onClick={() => setShowColSettings(false)} />
                <div className="absolute right-0 top-full mt-1 z-20 w-44 rounded-lg border border-gray-200 bg-white shadow-lg py-2">
                  <div className="px-3 pb-1 text-xs font-medium text-gray-400">显示列</div>
                  {ROSTER_COLUMNS.map(col => (
                    <label key={col.key} className="flex items-center gap-2 px-3 py-1.5 text-sm hover:bg-gray-50 cursor-pointer">
                      <input
                        type="checkbox"
                        checked={colVisible(col.key)}
                        onChange={() => colToggle(col.key)}
                        className="rounded border-gray-300"
                      />
                      <span className="text-gray-700">{col.label}</span>
                    </label>
                  ))}
                </div>
              </>
            )}
          </div>
        </div>
      </div>

      {selectedIds.size > 0 && (
        <div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/20 bg-primary/5 px-4 py-3">
          <span className="text-sm font-medium text-gray-700">已选择 {selectedIds.size} 名员工</span>
          <div className="flex flex-wrap gap-2">
            <Button variant="secondary" onClick={() => setShowBatchRenewModal(true)} className="shrink-0">
              <Check className="mr-1 h-4 w-4" />批量续签
            </Button>
            <Button variant="secondary" onClick={() => setShowBatchConfirmModal(true)} className="shrink-0">
              <CheckCircle className="mr-1 h-4 w-4" />批量转正
            </Button>
            <Button variant="secondary" onClick={() => setShowBatchCertModal(true)} className="shrink-0">
              <FileText className="mr-1 h-4 w-4" />批量开具证明
            </Button>
            <Button variant="danger" onClick={() => setShowBatchTerminateModal(true)} className="shrink-0">
              <UserX className="mr-1 h-4 w-4" />批量解聘
            </Button>
          </div>
        </div>
      )}

      {/* 合同风险提示 */}
      {!isLoading && (riskStats.expired > 0 || riskStats.unsigned > 0) && (
        <InlineAlert
          type="warning"
          title="合同风险提醒"
          closable
        >
          {riskStats.expired > 0 && <span>当前页有 <strong className="text-danger">{riskStats.expired}</strong> 人合同已到期；</span>}
          {riskStats.unsigned > 0 && <span><strong className="text-danger">{riskStats.unsigned}</strong> 人未签合同；</span>}
          <span className="text-gray-500">请及时处理以避免法律风险。</span>
        </InlineAlert>
      )}

      {/* 快捷筛选标签 */}
      {!isLoading && quickFilters.length > 0 && (
        <div className="flex flex-wrap items-center gap-2">
          <span className="text-xs text-gray-400">快捷筛选：</span>
          {quickFilters.map((f) => (
            <button
              key={f.key}
              onClick={() => {
                setFilterStatus(f.filter.status)
                setFilterContractStatus(f.filter.contractStatus)
                setFilterDepartment(f.filter.department)
                setPage(1)
              }}
              className={`px-2.5 py-1 rounded-full text-xs font-medium border transition-all hover:shadow-sm ${
                f.color === 'rose'
                  ? 'border-rose-200 bg-rose-50 text-rose-700 hover:bg-rose-100'
                  : 'border-amber-200 bg-amber-50 text-amber-700 hover:bg-amber-100'
              }`}
            >
              {f.label}（{f.count}）
            </button>
          ))}
        </div>
      )}

      {isLoading ? (
        <div className="rounded-lg border border-gray-200 bg-white py-16 text-center text-sm text-gray-400">加载中...</div>
      ) : isError ? (
        <QueryError error={error} onRetry={refetch} />
      ) : filtered.length === 0 ? (
        <Card><div className="py-12 text-center text-sm text-gray-400">暂无符合条件的员工</div></Card>
      ) : (
        <Card className="overflow-hidden p-0">
          <div className="overflow-x-auto">
            <table className="w-full min-w-[900px] text-sm">
              <thead className="bg-gray-50/90">
                <tr className="border-b border-gray-200 text-xs font-medium text-gray-500">
                  <th className="px-4 py-3 text-left w-8">
                    <input type="checkbox" checked={employees.length > 0 && selectedIds.size === employees.length} onChange={toggleSelectAll} />
                  </th>
                  <th className="px-4 py-3 text-left">姓名</th>
                  {colVisible('department') && <th className="px-4 py-3 text-left">部门</th>}
                  {colVisible('status') && <th className="px-4 py-3 text-left">状态</th>}
                  {colVisible('hireDate') && <th className="px-4 py-3 text-left">入职日期</th>}
                  <th className="hidden px-4 py-3 text-left">离职日期</th>
                  {colVisible('position') && <th className="px-4 py-3 text-left">职务</th>}
                  {colVisible('phone') && <th className="px-4 py-3 text-left">手机号</th>}
                  {colVisible('gender') && <th className="px-4 py-3 text-center">性别</th>}
                  {colVisible('contractType') && <th className="px-4 py-3 text-left">合同类型</th>}
                  {colVisible('contractStatus') && <th className="px-4 py-3 text-left">合同状态</th>}
                  {colVisible('contractExpiry') && <th className="px-4 py-3 text-left">合同到期</th>}
                  {colVisible('socialStatus') && <th className="px-4 py-3 text-left">社保状态</th>}
                  {colVisible('socialInsBase') && <th className="px-4 py-3 text-right">社保基数</th>}
                  {colVisible('socialInsAmount') && <th className="px-4 py-3 text-right">社保缴费</th>}
                  {colVisible('records') && <th className="px-4 py-3 text-center">记录</th>}
                  <th className="px-4 py-3 text-center">操作</th>
                </tr>
              </thead>
              <tbody>
                {employees.map((e: any, idx: number) => (
                  <tr
                    key={e.id}
                    className={`border-b border-gray-100 last:border-0 cursor-pointer transition-colors hover:bg-primary/[0.05] group ${idx % 2 === 1 ? 'bg-gray-100/60' : ''}`}
                    onClick={() => setSelectedId(e.id)}
                  >
                    <td className="px-4 py-2.5" onClick={(ev) => ev.stopPropagation()}>
                      <input type="checkbox" checked={selectedIds.has(e.id)} onChange={() => toggleSelect(e.id)} />
                    </td>
                    <td className="px-4 py-2.5">
                      <div className="flex flex-col gap-0.5">
                        <span className="font-medium text-gray-900 text-sm leading-tight">{e.name}</span>
                        <span className="text-gray-400 text-[11px] font-mono cursor-pointer hover:text-primary transition-colors leading-tight" title="点击复制完整证件号码" onClick={(ev) => {
                          ev.stopPropagation()
                          if (e.idCardNumber) {
                            copyToClipboard(e.idCardNumber, '已复制证件号码')
                          }
                        }}>{e.idCardNumber || '—'}</span>
                      </div>
                    </td>
                    {colVisible('department') && <td className="px-4 py-2.5 text-gray-500">{e.department}</td>}
                    {colVisible('status') && <td className="px-4 py-2.5">
                      <div className="flex flex-col gap-1">
                        <span className={`px-2 py-0.5 rounded text-xs w-fit ${
                          e.status === 'ACTIVE' ? 'bg-green-50 text-safe'
                          : e.status === 'PRE_HIRE' ? 'bg-blue-50 text-blue-600'
                          : 'bg-gray-100 text-gray-500'
                        }`}>
                          {e.status === 'ACTIVE' ? '在职' : e.status === 'PRE_HIRE' ? '预入职' : '离职'}
                        </span>
                        {e.probationInfo?.isProbation && (
                          <span className={`px-2 py-0.5 rounded text-xs w-fit ${
                            e.probationInfo.isExpiring
                              ? 'bg-orange-50 text-orange-700 border border-orange-200'
                              : 'bg-amber-50 text-amber-700 border border-amber-200'
                          }`}>
                            试用期{e.probationInfo.isExpiring ? `即将到期(${e.probationInfo.daysToConfirm}天)` : `剩${e.probationInfo.daysToConfirm}天`}
                          </span>
                        )}
                      </div>
                    </td>}
                    {colVisible('hireDate') && <td className="px-4 py-2.5 text-xs text-gray-500">{e.hireDate?.toString().slice(0, 10)}</td>}
                    <td className="hidden px-4 py-2.5 text-gray-500">
                      {e.hasTermination && e.latestTerminationDate && e.latestTerminationStatus !== 'CANCELLED' && e.latestTerminationStatus !== 'COMPLETED' ? (
                        <span className={e.status === 'RESIGNED' ? 'text-gray-500' : 'text-amber-600'}>
                          {e.latestTerminationDate.toString().slice(0, 10)}
                          {e.status === 'ACTIVE' && ' (预计)'}
                        </span>
                      ) : (
                        <span className="text-gray-300">—</span>
                      )}
                    </td>
                    {colVisible('position') && <td className="px-4 py-2.5 text-gray-500">{e.position || '—'}</td>}
                    {colVisible('phone') && <td className="px-4 py-2.5 text-xs text-gray-500">{e.phone || '—'}</td>}
                    {colVisible('gender') && <td className="px-4 py-2.5 text-center text-gray-500">{e.gender || '—'}</td>}
                    {colVisible('contractType') && <td className="px-4 py-2.5">
                      {(() => {
                        const typeConfig: Record<string, { label: string; style: string }> = {
                          FIXED: { label: '劳动合同-固定期', style: 'bg-blue-50 text-blue-700 border border-blue-200' },
                          UNFIXED: { label: '劳动合同-无固定期', style: 'bg-purple-50 text-purple-700 border border-purple-200' },
                          LABOR: { label: '劳务协议', style: 'bg-amber-50 text-amber-700 border border-amber-200' },
                          INTERNSHIP: { label: '实习协议', style: 'bg-teal-50 text-teal-700 border border-teal-200' },
                          DISPATCH: { label: '劳务派遣', style: 'bg-cyan-50 text-cyan-700 border border-cyan-200' },
                          OUTSOURCING: { label: '业务外包', style: 'bg-slate-50 text-slate-700 border border-slate-200' },
                          PARTTIME: { label: '兼职协议', style: 'bg-indigo-50 text-indigo-700 border border-indigo-200' },
                          UNSIGNED: { label: '未签合同', style: 'bg-gray-100 text-gray-500 border border-gray-200' },
                        }
                        const ct = e.latestContract?.contractType
                        const cfg = typeConfig[ct] || typeConfig.UNSIGNED
                        return <span className={`px-2 py-0.5 rounded text-xs ${cfg.style}`}>{cfg.label}</span>
                      })()}
                    </td>}
                    {colVisible('contractStatus') && <td className="px-4 py-2.5">
                      {(() => {
                        const tagStyles: Record<string, string> = {
                          expired: 'bg-red-50 text-danger',
                          unsigned_over_year: 'bg-red-50 text-danger',
                          unsigned_over_30: 'bg-red-50 text-danger',
                          unsigned: 'bg-yellow-50 text-yellow-700',
                          expiring: 'bg-yellow-50 text-yellow-700',
                          pending_sign: 'bg-yellow-50 text-yellow-700',
                          active: 'bg-green-50 text-safe',
                          unfixed: 'bg-green-50 text-safe',
                        }
                        const statusTextMap: Record<string, string> = {
                          expired: '已过期',
                          unsigned_over_year: '未签署(超1年)',
                          unsigned_over_30: '未签署(超30天)',
                          unsigned: '未签署',
                          expiring: '即将到期',
                          pending_sign: '待签署',
                          active: '正常',
                          unfixed: '正常',
                        }
                        const style = tagStyles[e.contractStatus] || 'bg-gray-100 text-gray-500'
                        const text = statusTextMap[e.contractStatus] || '无合同'
                        return <span className={`px-2 py-0.5 rounded text-xs ${style}`}>{text}</span>
                      })()}
                    </td>}
                    {colVisible('contractExpiry') && <td className="px-4 py-2.5 text-gray-500">
                      {(() => {
                        const endDate = e.latestContract?.endDate
                        if (!endDate) {
                          // 无固定期限合同显示"无固定期限"，否则显示"—"
                          if (e.latestContract?.contractType === 'UNFIXED') return <span className="text-xs text-gray-400">无固定期限</span>
                          return <span className="text-gray-300">—</span>
                        }
                        const end = new Date(endDate)
                        const today = new Date()
                        today.setHours(0, 0, 0, 0)
                        end.setHours(0, 0, 0, 0)
                        const diffDays = Math.ceil((end.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
                        const dateStr = end.toISOString().slice(0, 10)
                        if (diffDays < 0) return <span className="text-danger text-xs">{dateStr} (已过期)</span>
                        if (diffDays <= 30) return <span className="text-danger font-medium text-xs">{dateStr} ({diffDays}天)</span>
                        if (diffDays <= 90) return <span className="text-amber-600 text-xs">{dateStr} ({diffDays}天)</span>
                        return <span className="text-xs">{dateStr}</span>
                      })()}
                    </td>}
                    {colVisible('socialStatus') && <td className="px-4 py-2.5">
                      {(() => {
                        const status = e.socialInsuranceStatus
                        if (!status) return <span className="text-gray-300 text-xs">—</span>
                        const cfg: Record<string, { label: string; style: string }> = {
                          ACTIVE: { label: '在保', style: 'bg-green-50 text-safe' },
                          SUSPENDED: { label: '停保', style: 'bg-amber-50 text-amber-600' },
                          UNINSURED: { label: '未参保', style: 'bg-red-50 text-danger' },
                          PENDING: { label: '待办理', style: 'bg-blue-50 text-blue-600' },
                        }
                        const c = cfg[status] || { label: status, style: 'bg-gray-100 text-gray-500' }
                        return <span className={`px-2 py-0.5 rounded text-xs ${c.style}`}>{c.label}</span>
                      })()}
                    </td>}
                    {colVisible('socialInsBase') && <td className="px-4 py-2.5 text-right text-xs">
                      {e.socialInsBase ? e.socialInsBase.toLocaleString() : <span className="text-gray-300">—</span>}
                    </td>}
                    {colVisible('socialInsAmount') && <td className="px-4 py-2.5 text-right">
                      {(() => {
                        if (!e.socialInsCalc && !e.housingFundCalc) return <span className="text-gray-300 text-xs">—</span>
                        const socialEmp = e.socialInsCalc?.socialEmp || 0
                        const socialOrg = e.socialInsCalc?.socialOrg || 0
                        const housingEmp = e.housingFundCalc?.housingEmp || 0
                        const housingOrg = e.housingFundCalc?.housingOrg || 0
                        const totalEmp = socialEmp + housingEmp
                        const totalOrg = socialOrg + housingOrg
                        return (
                          <div className="flex flex-col gap-0.5 items-end">
                            <span className="text-xs text-gray-700 leading-tight">个人 {totalEmp.toFixed(2)}</span>
                            <span className="text-[11px] text-gray-400 leading-tight">企业 {totalOrg.toFixed(2)}</span>
                          </div>
                        )
                      })()}
                    </td>}
                    {colVisible('records') && <td className="px-4 py-2.5 text-center">
                      <div className="flex items-center justify-center gap-1 flex-wrap">
                        {(() => {
                          const items = [
                            { label: '违纪', count: e.counts?.disciplinaryRecords || 0, danger: true },
                            { label: '考勤', count: e.counts?.attendanceRecords || 0 },
                            { label: '培训', count: e.counts?.trainingRecords || 0 },
                            { label: '绩效', count: e.counts?.performanceRecords || 0 },
                            { label: '工资条', count: e.counts?.payslips || 0 },
                          ]
                          return items.map((it, i) => (
                            <span
                              key={i}
                              className={`text-xs px-1.5 py-0.5 rounded ${it.count > 0 ? (it.danger ? 'bg-red-50 text-danger' : 'bg-gray-100 text-gray-600') : 'text-gray-300'}`}
                            >
                              {it.label}{it.count}
                            </span>
                          ))
                        })()}
                      </div>
                    </td>}
                    <td className="px-3 py-2 text-center">
                      {e.status === 'ACTIVE' && (!e.hasTermination || e.latestTerminationStatus === 'CANCELLED' || e.latestTerminationStatus === 'COMPLETED') && (
                        <div className="flex flex-col items-center gap-1.5">
                          <div className="flex items-center justify-center gap-0.5">
                            <button
                              type="button"
                              title="调薪"
                              aria-label={`为${e.name}调薪`}
                              className="rounded-md p-1 text-gray-500 transition hover:bg-primary/10 hover:text-primary"
                              onClick={(ev) => {
                                ev.stopPropagation()
                                setSalaryEmployee(e)
                                setShowSalaryModal(true)
                              }}
                            >
                              <DollarSign className="h-3.5 w-3.5" />
                            </button>
                            {/* 试用期员工显示转正按钮 */}
                            {e.probationInfo?.isProbation && (
                              <button
                                type="button"
                                title="转正"
                                aria-label={`为${e.name}办理转正`}
                                className="rounded-md p-1 text-gray-500 transition hover:bg-primary/10 hover:text-primary"
                                onClick={(ev) => {
                                  ev.stopPropagation()
                                  setConfirmEmployee(e)
                                  setShowConfirmModal(true)
                                }}
                              >
                                <CheckCircle className="h-3.5 w-3.5" />
                              </button>
                            )}
                            <button
                              type="button"
                              title="调动"
                              aria-label={`为${e.name}调动`}
                              className="rounded-md p-1 text-gray-500 transition hover:bg-primary/10 hover:text-primary"
                              onClick={(ev) => {
                                ev.stopPropagation()
                                setDeptEmployee(e)
                                setShowDeptModal(true)
                              }}
                            >
                              <Building2 className="h-3.5 w-3.5" />
                            </button>
                          </div>
                          <div className="flex items-center justify-center gap-0.5 border-t border-gray-100 pt-1.5">
                            <button
                              type="button"
                              title="开具证明"
                              aria-label={`为${e.name}开具证明`}
                              className="rounded-md p-1 text-gray-500 transition hover:bg-primary/10 hover:text-primary"
                              onClick={(ev) => {
                                ev.stopPropagation()
                                setCertEmployee(e)
                                setCertPurpose('')
                                setCertType('INCOME_CERT')
                                setShowCertModal(true)
                              }}
                            >
                              <FileText className="h-3.5 w-3.5" />
                            </button>
                            {(e.contractStatus === 'expiring' || e.contractStatus === 'expired') && (
                            <button
                              type="button"
                              title="续签合同"
                              aria-label={`为${e.name}续签合同`}
                              className="rounded-md p-1 text-gray-500 transition hover:bg-primary/10 hover:text-primary"
                              onClick={(ev) => {
                                ev.stopPropagation()
                                // 自动推导新合同开始日期：原合同结束日 + 1天
                                const oldEndDate = e.latestContract?.endDate
                                let newStart = new Date().toISOString().slice(0, 10)
                                if (oldEndDate) {
                                  const d = new Date(oldEndDate)
                                  d.setDate(d.getDate() + 1)
                                  newStart = d.toISOString().slice(0, 10)
                                }
                                setRenewEmployee(e)
                                setRenewNewStartDate(newStart)
                                setRenewNewEndDate('')
                                setRenewNewSalary(e.monthlySalary ? String(e.monthlySalary) : '')
                                setShowRenewModal(true)
                              }}
                            >
                              <RotateCcw className="h-3.5 w-3.5" />
                            </button>
                            )}
                            <button
                              type="button"
                              title="离职"
                              aria-label={`为${e.name}办理离职`}
                              className="rounded-md p-1 text-gray-500 transition hover:bg-danger/10 hover:text-danger"
                              onClick={(ev) => {
                                ev.stopPropagation()
                                setResignEmployee(e)
                                setShowResignModal(true)
                              }}
                            >
                              <UserX className="h-3.5 w-3.5" />
                            </button>
                          </div>
                        </div>
                      )}
                      {e.hasTermination && e.status === 'ACTIVE' && e.latestTerminationStatus !== 'CANCELLED' && e.latestTerminationStatus !== 'COMPLETED' && (
                        <div className="flex items-center justify-center gap-2">
                          <span className={`text-xs ${e.latestTerminationType === 'RESIGNATION' ? 'text-blue-600' : 'text-amber-600'}`}>
                            {e.latestTerminationType === 'RESIGNATION' ? '待离职' : '待解聘'}
                          </span>
                          <button
                            type="button"
                            title="撤回"
                            aria-label={`撤回${e.name}的${e.latestTerminationType === 'RESIGNATION' ? '离职' : '解聘'}记录`}
                            className="rounded-md p-1.5 text-gray-400 transition hover:bg-danger/10 hover:text-danger"
                            onClick={async (ev) => {
                              ev.stopPropagation()
                              if (e.latestTerminationId && await confirm({
                                title: '撤回确认',
                                message: `确认撤回${e.latestTerminationType === 'RESIGNATION' ? '离职' : '解聘'}记录？`,
                              })) {
                                revokeMutation.mutate(e.latestTerminationId)
                              }
                            }}
                          >
                            <RotateCcw className="h-4 w-4" />
                          </button>
                        </div>
                      )}
                      {e.status === 'RESIGNED' && (
                        <button
                          type="button"
                          title="重新入职"
                          aria-label={`为${e.name}办理重新入职`}
                          className="rounded-md p-1.5 text-primary transition hover:bg-primary/10 hover:text-primary/80"
                          onClick={(ev) => {
                            ev.stopPropagation()
                            setRehireEmployee(e)
                            setShowRehireModal(true)
                          }}
                        >
                          <UserPlus className="h-4 w-4" />
                        </button>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="border-t border-gray-100 px-5 py-3">
            <Pagination
              page={pagination.page}
              pageSize={pageSize}
              total={pagination.total}
              onPageChange={(p) => setPage(p)}
              onPageSizeChange={() => setPage(1)}
            />
          </div>
        </Card>
      )}

      {showAddModal && (
        <AddEmployeeModal
          onClose={() => setShowAddModal(false)}
          onSubmit={(data) => addMutation.mutate(data)}
          loading={addMutation.isPending}
          error={addMutation.error as any}
        />
      )}

      {showImportModal && (
        <Modal open={showImportModal} onClose={() => setShowImportModal(false)} title="批量导入" size="lg">
          <ImportSettings />
        </Modal>
      )}

      {showResignModal && resignEmployee && (
        <ResignModal
          employee={resignEmployee}
          onClose={() => { setShowResignModal(false); setResignEmployee(null) }}
          onSubmit={(data) => resignMutation.mutate(data)}
          loading={resignMutation.isPending}
          error={resignMutation.error as any}
        />
      )}

      {showRehireModal && rehireEmployee && (
        <RehireModal
          employee={rehireEmployee}
          onClose={() => { setShowRehireModal(false); setRehireEmployee(null) }}
          onSubmit={(data) => rehireMutation.mutate(data)}
          loading={rehireMutation.isPending}
          error={rehireMutation.error as any}
        />
      )}

      {showSalaryModal && salaryEmployee && (
        <SalaryChangeModal
          employee={salaryEmployee}
          onClose={() => { setShowSalaryModal(false); setSalaryEmployee(null) }}
          onSubmit={(data) => salaryChangeMutation.mutate(data)}
          loading={salaryChangeMutation.isPending}
          error={salaryChangeMutation.error as any}
        />
      )}

      {showDeptModal && deptEmployee && (
        <DeptChangeModal
          employee={deptEmployee}
          onClose={() => { setShowDeptModal(false); setDeptEmployee(null) }}
          onSubmit={(data) => deptChangeMutation.mutate(data)}
          loading={deptChangeMutation.isPending}
          error={deptChangeMutation.error as any}
        />
      )}

      {showConfirmModal && confirmEmployee && (
        <ConfirmModal
          employee={confirmEmployee}
          onClose={() => { setShowConfirmModal(false); setConfirmEmployee(null) }}
          onSubmit={(data) => confirmMutation.mutate(data)}
          loading={confirmMutation.isPending}
          error={confirmMutation.error as any}
        />
      )}

      {/* 开具证明弹窗 */}
      {showCertModal && certEmployee && (
        <Modal open={showCertModal} onClose={() => { setShowCertModal(false); setCertEmployee(null) }} title={`为 ${certEmployee.name}${certEmployee.idCardNumber ? `（${certEmployee.idCardNumber}）` : ''} 开具证明`}>
          <div className="space-y-3">
            <div>
              <Label>证明类型</Label>
              <Select value={certType} onChange={(e) => setCertType(e.target.value)}>
                <option value="INCOME_CERT">收入证明</option>
                <option value="EMPLOYMENT_CERT">在职证明</option>
                <option value="LEAVING_CERT">离职证明</option>
              </Select>
            </div>
            <div className="text-xs text-gray-500">
              将自动填充员工姓名、证件号码、职务等信息，并直接生成证明文书。
            </div>
            <div>
              <Label>用途（选填）</Label>
              <Input value={certPurpose} onChange={(e) => setCertPurpose(e.target.value)} placeholder="如：办理签证、租房、贷款等" />
            </div>
            <div className="flex justify-end gap-2">
              <Button variant="secondary" onClick={() => { setShowCertModal(false); setCertEmployee(null) }}>取消</Button>
              <Button
                disabled={certMutation.isPending}
                onClick={() => {
                  certMutation.mutate({
                    employeeId: certEmployee.id,
                    formData: {
                      employeeId: certEmployee.id,
                      employeeName: certEmployee.name,
                      idCardNumber: certEmployee.idCardNumber || '',
                      position: certEmployee.position || '',
                      monthlyIncome: certEmployee.monthlySalary ? `¥${certEmployee.monthlySalary}` : '',
                      purpose: certPurpose || '通用',
                    },
                  })
                }}
              >确认开具</Button>
            </div>
          </div>
        </Modal>
      )}

      {/* 续签合同弹窗 */}
      {showRenewModal && renewEmployee && (
        <Modal open={showRenewModal} onClose={() => { setShowRenewModal(false); setRenewEmployee(null) }} title={`为 ${renewEmployee.name}${renewEmployee.idCardNumber ? `（${renewEmployee.idCardNumber}）` : ''} 续签合同`}>
          <div className="space-y-3">
            <div className="text-xs text-gray-500">
              原合同到期日：{renewEmployee.latestContract?.endDate ? new Date(renewEmployee.latestContract.endDate).toISOString().slice(0, 10) : '无'}
            </div>
            <div>
              <Label>新合同开始日期 *</Label>
              <Input type="date" value={renewNewStartDate} onChange={(e) => setRenewNewStartDate(e.target.value)} />
            </div>
            <div>
              <Label>新合同结束日期</Label>
              <Input type="date" value={renewNewEndDate} onChange={(e) => setRenewNewEndDate(e.target.value)} placeholder="留空表示无固定期限" />
            </div>
            <div>
              <Label>新薪资（选填）</Label>
              <Input type="number" value={renewNewSalary} onChange={(e) => setRenewNewSalary(e.target.value)} placeholder="续签后月薪" />
            </div>
            <div className="flex justify-end gap-2">
              <Button variant="secondary" onClick={() => { setShowRenewModal(false); setRenewEmployee(null) }}>取消</Button>
              <Button
                disabled={renewMutation.isPending}
                onClick={() => {
                  if (!renewNewStartDate) {
                    toast.error('请填写新合同开始日期')
                    return
                  }
                  if (renewNewEndDate && renewNewEndDate < renewNewStartDate) {
                    toast.error('结束日期不能早于开始日期')
                    return
                  }
                  renewMutation.mutate({
                    employeeId: renewEmployee.id,
                    formData: {
                      employeeId: renewEmployee.id,
                      oldContractId: renewEmployee.latestContract?.id || '',
                      newStartDate: renewNewStartDate,
                      newEndDate: renewNewEndDate || undefined,
                      newSalary: renewNewSalary || undefined,
                    },
                  })
                }}
              >确认续签</Button>
            </div>
          </div>
        </Modal>
      )}

      {/* 批量转正弹窗 */}
      {showBatchConfirmModal && (
        <Modal open={showBatchConfirmModal} onClose={() => setShowBatchConfirmModal(false)} title="批量转正">
          <div className="space-y-3">
            <div className="text-xs text-gray-500">
              将为选中的 {selectedIds.size} 名员工中的试用期员工创建转正草稿。
            </div>
            <div>
              <Label>转正日期</Label>
              <Input type="date" value={batchConfirmDate} onChange={(e) => setBatchConfirmDate(e.target.value)} />
            </div>
            <div>
              <Label>转正薪资（选填，留空则不调整）</Label>
              <Input type="number" value={batchConfirmSalary} onChange={(e) => setBatchConfirmSalary(e.target.value)} placeholder="转正后月薪" />
            </div>
            <div className="flex justify-end gap-2">
              <Button variant="secondary" onClick={() => setShowBatchConfirmModal(false)}>取消</Button>
              <Button onClick={handleBatchConfirm}>确认转正</Button>
            </div>
          </div>
        </Modal>
      )}

      {/* 批量开具证明弹窗 */}
      {showBatchCertModal && (
        <Modal open={showBatchCertModal} onClose={() => setShowBatchCertModal(false)} title="批量开具证明">
          <div className="space-y-3">
            <div className="text-xs text-gray-500">
              将为选中的 {selectedIds.size} 名员工批量生成证明文书，可在「证据管理」中查看和下载。
            </div>
            <div>
              <Label>证明类型</Label>
              <Select value={batchCertType} onChange={(e) => setBatchCertType(e.target.value)}>
                <option value="INCOME_CERT">收入证明</option>
                <option value="EMPLOYMENT_CERT">在职证明</option>
                <option value="LEAVING_CERT">离职证明</option>
              </Select>
            </div>
            <div className="flex justify-end gap-2">
              <Button variant="secondary" onClick={() => setShowBatchCertModal(false)}>取消</Button>
              <Button onClick={handleBatchCert}>确认开具</Button>
            </div>
          </div>
        </Modal>
      )}

      {showBatchRenewModal && (
        <Modal open={showBatchRenewModal} onClose={() => { setShowBatchRenewModal(false); setPreviewData(null); }} title="批量续签">
          <div className="space-y-3">
            {!previewData ? (
              <>
                <p className="text-xs text-gray-500">已选择 {selectedIds.size} 名员工，将为其续签劳动合同。</p>
                <div>
                  <Label>续签年限</Label>
                  <Select value={String(batchRenewYears)} onChange={(e) => setBatchRenewYears(Number(e.target.value))}>
                    <option value="1">1年</option>
                    <option value="2">2年</option>
                    <option value="3">3年</option>
                    <option value="5">5年</option>
                  </Select>
                </div>
                {previewRenewMutation.error && (
                  <div className="px-3 py-2 rounded-md bg-red-50 text-red-700 text-xs">
                    {(previewRenewMutation.error as any)?.response?.data?.error?.message || '预检失败'}
                  </div>
                )}
                <div className="flex justify-end gap-2">
                  <Button variant="secondary" onClick={() => { setShowBatchRenewModal(false); setPreviewData(null); }}>取消</Button>
                  <Button
                    onClick={() => {
                      const contractIds = employees
                        .filter((e: any) => selectedIds.has(e.id) && e.latestContract?.id)
                        .map((e: any) => e.latestContract.id)
                      if (contractIds.length === 0) {
                        toast.error('所选员工没有可续签的合同')
                        return
                      }
                      previewRenewMutation.mutate(contractIds)
                    }}
                    disabled={previewRenewMutation.isPending}
                  >
                    {previewRenewMutation.isPending ? '预检中...' : '合规预检'}
                  </Button>
                </div>
              </>
            ) : (
              <>
                <div className="flex items-center justify-between">
                  <p className="text-xs font-medium">合规预检结果</p>
                  <span className={`text-xs px-2 py-0.5 rounded ${previewData.warnings > 0 ? 'bg-amber-100 text-amber-700' : 'bg-green-100 text-green-700'}`}>
                    {previewData.warnings > 0 ? `${previewData.warnings} 项风险提示` : '全部通过'}
                  </span>
                </div>
                <div className="max-h-64 overflow-y-auto space-y-2">
                  {previewData.results.map((r: any) => (
                    <div key={r.contractId} className={`p-2 rounded text-xs ${r.warning ? 'bg-amber-50 border border-amber-200' : 'bg-gray-50'}`}>
                      <div className="flex items-center justify-between">
                        <span className="font-medium">{r.employeeName}{r.employeeIdCardNumber ? <span className="ml-1 font-mono text-gray-400 text-[10px]">{r.employeeIdCardNumber}</span> : null}</span>
                        <span className="text-gray-400">{r.department}</span>
                      </div>
                      <div className="text-gray-500 mt-1">
                        第 {r.renewalCount} 次续签 · 在职 {r.yearsSinceHire} 年
                      </div>
                      {r.warning && (
                        <div className="mt-1 text-amber-600">{r.warning}</div>
                      )}
                      <div className="mt-1 text-gray-500">{r.suggestion}</div>
                    </div>
                  ))}
                </div>
                {previewData.warnings > 0 && (
                  <div className="px-3 py-2 rounded-md bg-amber-50 text-amber-700 text-xs">
                    存在法律风险，建议处理后再继续操作
                  </div>
                )}
                {batchRenewMutation.error && (
                  <div className="px-3 py-2 rounded-md bg-red-50 text-red-700 text-xs">
                    {(batchRenewMutation.error as any)?.response?.data?.error?.message || '续签失败'}
                  </div>
                )}
                <div className="flex justify-end gap-2">
                  <Button variant="secondary" onClick={() => setPreviewData(null)}>返回修改</Button>
                  <Button
                    onClick={() => {
                      const contractIds = employees
                        .filter((e: any) => selectedIds.has(e.id) && e.latestContract?.id)
                        .map((e: any) => e.latestContract.id)
                      batchRenewMutation.mutate({ contractIds, years: batchRenewYears })
                    }}
                    disabled={batchRenewMutation.isPending}
                  >
                    {batchRenewMutation.isPending ? '续签中...' : `确认续签 ${selectedIds.size} 人`}
                  </Button>
                </div>
              </>
            )}
          </div>
        </Modal>
      )}

      {showBatchTerminateModal && (
        <Modal open={showBatchTerminateModal} onClose={() => { setShowBatchTerminateModal(false); setTerminatePreviewData(null); }} title="批量解聘" size="lg">
          <div className="space-y-3">
            {!terminatePreviewData ? (
              <>
                <p className="text-xs text-gray-500">已选择 {selectedIds.size} 名员工进行批量解聘。</p>
                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label>解聘日期</Label>
                    <Input type="date" value={batchTerminateDate} onChange={(e) => setBatchTerminateDate(e.target.value)} />
                  </div>
                  <div>
                    <Label>解聘原因</Label>
                    <Select value={batchTerminateReason} onChange={(e) => setBatchTerminateReason(e.target.value)}>
                      <option value="NEGOTIATED">协商解除</option>
                      <option value="LAYOFF">经济性裁员</option>
                      <option value="NONFAULT">非过错解除</option>
                      <option value="FAULT">过错解除</option>
                      <option value="EXPIRED">合同到期不续签</option>
                    </Select>
                  </div>
                </div>
                {previewTerminateMutation.error && (
                  <div className="px-3 py-2 rounded-md bg-red-50 text-red-700 text-xs">
                    {(previewTerminateMutation.error as any)?.response?.data?.error?.message || '预检失败'}
                  </div>
                )}
                <div className="flex justify-end gap-2">
                  <Button variant="secondary" onClick={() => { setShowBatchTerminateModal(false); setTerminatePreviewData(null); }}>取消</Button>
                  <Button
                    onClick={() => {
                      const items = Array.from(selectedIds).map(id => ({
                        employeeId: id,
                        reason: batchTerminateReason,
                        terminationDate: batchTerminateDate,
                      }))
                      previewTerminateMutation.mutate(items)
                    }}
                    disabled={previewTerminateMutation.isPending}
                  >
                    {previewTerminateMutation.isPending ? '预检中...' : '合规预检'}
                  </Button>
                </div>
              </>
            ) : (
              <>
                <div className="flex items-center justify-between">
                  <p className="text-xs font-medium">合规预检结果</p>
                  <span className={`text-xs px-2 py-0.5 rounded ${terminatePreviewData.warnings > 0 ? 'bg-red-100 text-red-700' : 'bg-green-100 text-green-700'}`}>
                    {terminatePreviewData.warnings > 0 ? `${terminatePreviewData.warnings} 项风险提示` : '全部通过'}
                  </span>
                </div>
                <div className="max-h-64 overflow-y-auto space-y-2">
                  {terminatePreviewData.results.map((r: any) => (
                    <div key={r.employeeId} className={`p-2 rounded text-xs ${r.warnings.length > 0 ? 'bg-red-50 border border-red-200' : 'bg-gray-50'}`}>
                      <div className="flex items-center justify-between">
                        <span className="font-medium">{r.employeeName}{r.employeeIdCardNumber ? <span className="ml-1 font-mono text-gray-400 text-[10px]">{r.employeeIdCardNumber}</span> : null}</span>
                        <span className="text-gray-400">{r.department}</span>
                      </div>
                      <div className="text-gray-500 mt-1">
                        {terminateReasonMap[r.reason] || r.reason} · {r.terminationDate}
                      </div>
                      {r.warnings.length > 0 && r.warnings.map((w: string, i: number) => (
                        <div key={i} className="mt-1 text-red-600">{w}</div>
                      ))}
                    </div>
                  ))}
                </div>
                {terminatePreviewData.warnings > 0 && (
                  <div className="px-3 py-2 rounded-md bg-red-50 text-red-700 text-xs">
                    存在法律风险，建议处理后再继续操作
                  </div>
                )}
                {batchTerminateMutation.error && (
                  <div className="px-3 py-2 rounded-md bg-red-50 text-red-700 text-xs">
                    {(batchTerminateMutation.error as any)?.response?.data?.error?.message || '解聘失败'}
                  </div>
                )}
                <div className="flex justify-end gap-2">
                  <Button variant="secondary" onClick={() => setTerminatePreviewData(null)}>返回修改</Button>
                  <Button
                    variant="danger"
                    onClick={() => {
                      const items = Array.from(selectedIds).map(id => ({
                        employeeId: id,
                        reason: batchTerminateReason,
                        terminationDate: batchTerminateDate,
                      }))
                      batchTerminateMutation.mutate(items)
                    }}
                    disabled={batchTerminateMutation.isPending}
                  >
                    {batchTerminateMutation.isPending ? '解聘中...' : `确认解聘 ${selectedIds.size} 人`}
                  </Button>
                </div>
              </>
            )}
          </div>
        </Modal>
      )}

      {/* 签署方式选择弹窗 */}
      {signChoice?.open && (
        <SignMethodChoice
          open={signChoice.open}
          onClose={() => setSignChoice(null)}
          employeeId={signChoice.employeeId}
          employeeName={signChoice.employeeName}
          employeeIdCardNumber={signChoice.employeeIdCardNumber}
          scene={signChoice.scene}
          documentTitle={signChoice.documentTitle}
          contractId={signChoice.contractId}
          remark={signChoice.remark}
          actionName={signChoice.actionName}
        />
      )}
    </div>
  )
}
