import prisma from '../lib/prisma'
import { encrypt, decrypt, sha256 } from '../lib/crypto'
import { runRiskDetection } from './risk.service'
import { extractBirthDateFromIdCard, extractGenderFromIdCard } from './retirement.service'
import bcrypt from 'bcryptjs'

function daysBetween(a: Date, b: Date): number {
  return Math.floor((a.getTime() - b.getTime()) / (1000 * 60 * 60 * 24))
}

function dateToMonth(date: Date): string {
  const y = date.getFullYear()
  const m = String(date.getMonth() + 1).padStart(2, '0')
  return `${y}-${m}`
}

/** 安全解密数字（工资字段） */
function safeDecryptNum(encrypted: string): number {
  try {
    return Number(decrypt(encrypted)) || 0
  } catch {
    return Number(encrypted) || 0
  }
}

async function clampSocialInsBase(orgId: string, base: number, city?: string, accountId?: string): Promise<number> {
  // 优先按账户查年度标准
  if (accountId) {
    const standard = await prisma.socialYearStandard.findFirst({
      where: { accountId, isCurrent: true },
      orderBy: { effectiveFrom: 'desc' },
    })
    if (standard) return Math.min(Math.max(base, standard.baseMin), standard.baseMax)
  }
  // 回退到旧配置表
  const config = await prisma.socialInsuranceConfig.findFirst({
    where: { orgId, ...(city ? { city } : {}) },
    orderBy: { effectiveFrom: 'desc' },
  })
  if (config) return Math.min(Math.max(base, config.baseMin), config.baseMax)
  return base
}

async function clampHousingFundBase(orgId: string, base: number, city?: string, accountId?: string): Promise<number> {
  // 优先按账户查年度标准
  if (accountId) {
    const standard = await prisma.socialYearStandard.findFirst({
      where: { accountId, isCurrent: true },
      orderBy: { effectiveFrom: 'desc' },
    })
    if (standard) {
      // 公积金专用上下限（housingBaseMin/Max），为0时回退到社保的 baseMin/baseMax
      const min = standard.housingBaseMin > 0 ? standard.housingBaseMin : standard.baseMin
      const max = standard.housingBaseMax > 0 ? standard.housingBaseMax : standard.baseMax
      return Math.min(Math.max(base, min), max)
    }
  }
  // 回退到旧配置表
  const config = await prisma.housingFundConfig.findFirst({
    where: { orgId, ...(city ? { city } : {}) },
    orderBy: { effectiveFrom: 'desc' },
  })
  if (config) return Math.min(Math.max(base, config.baseMin), config.baseMax)
  return base
}

export function prevMonth(month: string): string {
  const [y, m] = month.split('-').map(Number)
  const d = new Date(y, m - 2, 1)
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
}

/**
 * 身份证有效性校验（GB 11643-1999）：格式 + 校验位 + 出生日期合法性
 * @returns null=有效，string=错误原因
 */
export function validateIdCard(idCard: string): string | null {
  if (!idCard) return null
  if (idCard.length !== 18) return '证件号码必须为18位'
  if (!/^\d{17}[\dXx]$/.test(idCard)) return '证件号码格式错误：前17位必须为数字，第18位为数字或X'
  const WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  const CHECK_CODES = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  const sum = idCard.substring(0, 17).split('').reduce((s, c, i) => s + parseInt(c) * WEIGHTS[i], 0)
  if (idCard[17].toUpperCase() !== CHECK_CODES[sum % 11]) return '证件号码校验位错误'
  const birthYear = parseInt(idCard.substring(6, 10))
  const birthMonth = parseInt(idCard.substring(10, 12))
  const birthDay = parseInt(idCard.substring(12, 14))
  if (birthMonth < 1 || birthMonth > 12 || birthDay < 1 || birthDay > 31) return '证件号码出生日期非法'
  const birthDate = new Date(birthYear, birthMonth - 1, birthDay)
  if (isNaN(birthDate.getTime()) || birthDate.getFullYear() !== birthYear || birthDate.getMonth() !== birthMonth - 1 || birthDate.getDate() !== birthDay) return '证件号码出生日期不存在'
  if (birthDate > new Date()) return '证件号码出生日期晚于今天'
  return null
}

/**
 * 从身份证计算年龄（周岁）
 */
export function getAgeFromIdCard(idCard: string, referenceDate: Date = new Date()): number | null {
  if (!idCard || idCard.length !== 18) return null
  const birthYear = parseInt(idCard.substring(6, 10))
  const birthMonth = parseInt(idCard.substring(10, 12))
  const birthDay = parseInt(idCard.substring(12, 14))
  if (isNaN(birthYear) || isNaN(birthMonth) || isNaN(birthDay)) return null
  let age = referenceDate.getFullYear() - birthYear
  const monthDiff = referenceDate.getMonth() - (birthMonth - 1)
  if (monthDiff < 0 || (monthDiff === 0 && referenceDate.getDate() < birthDay)) age--
  return age
}

/**
 * 判定是否超龄（达法定退休年龄）：男60，女干部55，女工人50（未选类型按50）
 */
export function isOverageEmployee(idCard: string, gender: string, femaleWorkerType?: string | null): boolean {
  const age = getAgeFromIdCard(idCard)
  if (age === null) return false
  if (gender === '男') return age >= 60
  return age >= (femaleWorkerType === 'CADRE' ? 55 : 50)
}

export function getContractStatus(contract: {
  signDate: Date | null
  startDate: Date
  endDate: Date | null
  contractType: string
  hireDate: Date
  /** hasRecord: 是否存在合同记录（区分"有合同但未填签订日期"和"完全无合同"） */
  hasRecord?: boolean
}): { status: string; statusText: string; riskLevel: 'high' | 'medium' | 'low' | 'safe' } {
  const today = new Date()
  const typeLabelMap: Record<string, string> = {
    FIXED: '固定期限',
    UNFIXED: '无固定期限',
    LABOR: '劳务协议',
    INTERNSHIP: '实习协议',
    UNSIGNED: '',
  }
  const typeLabel = typeLabelMap[contract.contractType] || ''

  // 只有真正没有合同记录（hasRecord=false）或类型为 UNSIGNED 时，才判定为"未签合同"
  // 有合同记录但 signDate 为 null 时，不再判定为"未签合同"
  const isUnsigned = contract.contractType === 'UNSIGNED' || (contract.hasRecord === false && !contract.signDate)

  if (isUnsigned) {
    const days = daysBetween(today, contract.hireDate)
    if (days > 365) {
      return { status: 'unsigned_over_year', statusText: '未签合同(已视为无固定期限)', riskLevel: 'high' }
    } else if (days > 30) {
      return { status: 'unsigned_over_30', statusText: `未签合同(${days}天)`, riskLevel: 'high' }
    }
    return { status: 'unsigned', statusText: `未签合同(${days}天)`, riskLevel: 'medium' }
  }

  // 有合同记录（FIXED/UNFIXED/LABOR/INTERNSHIP）但未填签署日期 → 待签署
  // 电子签署完成后会回写 signDate，故 signDate 为空即视为未签署
  if (!contract.signDate) {
    if (contract.endDate) {
      const daysToExpire = daysBetween(contract.endDate, today)
      if (daysToExpire < 0) {
        return { status: 'pending_sign', statusText: `${typeLabel}·待签署（已到期）`, riskLevel: 'high' }
      } else if (daysToExpire <= 30) {
        return { status: 'pending_sign', statusText: `${typeLabel}·待签署（${daysToExpire}天到期）`, riskLevel: 'medium' }
      }
    }
    return { status: 'pending_sign', statusText: `${typeLabel}·待签署`, riskLevel: 'medium' }
  }

  // 已签署合同：按到期日判定
  if (contract.endDate) {
    const daysToExpire = daysBetween(contract.endDate, today)
    if (daysToExpire < 0) {
      return { status: 'expired', statusText: `${typeLabel}·已到期未续签`, riskLevel: 'high' }
    } else if (daysToExpire <= 30) {
      return { status: 'expiring', statusText: `${typeLabel}·即将到期(${daysToExpire}天)`, riskLevel: 'medium' }
    }
    return { status: 'active', statusText: `${typeLabel}·正常`, riskLevel: 'safe' }
  }

  // 无固定期限或有合同但无结束日期
  if (contract.contractType === 'UNFIXED') {
    return { status: 'unfixed', statusText: '无固定期限·正常', riskLevel: 'safe' }
  }

  // 有合同记录但未填结束日期（如 FIXED 但 endDate 为 null），视为正常
  return { status: 'active', statusText: `${typeLabel}·正常`, riskLevel: 'safe' }
}

export function validateProbation(contractMonths: number, probationMonths: number): { valid: boolean; max: number; message?: string } {
  let max = 0
  if (contractMonths >= 36) max = 6
  else if (contractMonths >= 12) max = 2
  else if (contractMonths >= 3) max = 1

  if (probationMonths > max) {
    return {
      valid: false,
      max,
      message: `${contractMonths}个月合同试用期最多${max}个月，当前${probationMonths}个月不合法`,
    }
  }
  return { valid: true, max }
}

/**
 * 判定员工在指定参考日期是否仍处于试用期。
 * 试用期结束日 = 合同开始日期 + 试用期月数；若结束日 > 参考日期，则仍在试用期。
 *
 * @param contract 合同记录（需含 startDate、probationMonths、probationSalary）
 * @param referenceDate 参考日期，默认当前日期；批次场景应传批次月份的月末
 * @returns true=仍在试用期，false=已转正或无试用期
 *
 * 注意：判定依据是"试用期是否结束"，而非"入职是否满 1 年"。
 * 旧逻辑 `startDate > now - 365d` 是错误的，转正后仍会用 probationSalary。
 */
export function isInProbation(
  contract: { startDate: Date | string | null; probationMonths: number | null } | null | undefined,
  referenceDate: Date = new Date(),
): boolean {
  if (!contract || !contract.startDate || !contract.probationMonths || contract.probationMonths <= 0) {
    return false
  }
  const start = new Date(contract.startDate)
  if (isNaN(start.getTime())) return false
  const probationEnd = new Date(start)
  probationEnd.setMonth(probationEnd.getMonth() + contract.probationMonths)
  return probationEnd > referenceDate
}

export async function getEmployees(orgId: string, params: { page?: number; pageSize?: number; search?: string; department?: string }) {
  const page = params.page || 1
  const pageSize = params.pageSize || 20
  const skip = (page - 1) * pageSize

  const where: any = { orgId, status: 'ACTIVE' }
  if (params.search) {
    where.OR = [
      { name: { contains: params.search } },
      { phone: { contains: params.search } },
    ]
  }
  if (params.department) {
    where.department = params.department
  }

  const [total, employees] = await Promise.all([
    prisma.employee.count({ where }),
    prisma.employee.findMany({
      where,
      include: {
        contracts: { orderBy: { createdAt: 'desc' }, take: 1 },
      },
      orderBy: { createdAt: 'desc' },
      skip,
      take: pageSize,
    }),
  ])

  const items = employees.map((emp) => {
    const latestContract = emp.contracts[0]
    const contractInfo = latestContract
      ? getContractStatus({
          signDate: latestContract.signDate,
          startDate: latestContract.startDate,
          endDate: latestContract.endDate,
          contractType: latestContract.contractType,
          hireDate: emp.hireDate,
          hasRecord: true,
        })
      : getContractStatus({
          signDate: null,
          startDate: emp.hireDate,
          endDate: null,
          contractType: 'UNSIGNED',
          hireDate: emp.hireDate,
          hasRecord: false,
        })

    let decryptedSalary = 0
    try {
      decryptedSalary = Number(decrypt(emp.monthlySalary)) || 0
    } catch {
      decryptedSalary = Number(emp.monthlySalary) || 0
    }
    // 解密工资结构
    const decryptedBaseSalary = emp.baseSalary ? safeDecryptNum(emp.baseSalary) : null
    const decryptedPerformanceSalary = emp.performanceSalary ? safeDecryptNum(emp.performanceSalary) : null

    return {
      id: emp.id,
      name: emp.name,
      department: emp.department,
      hireDate: emp.hireDate.toISOString().slice(0, 10),
      status: emp.status,
      monthlySalary: decryptedSalary,
      baseSalary: decryptedBaseSalary,
      performanceSalary: decryptedPerformanceSalary,
      contractStatus: contractInfo.status,
      contractStatusText: contractInfo.statusText,
      riskLevel: contractInfo.riskLevel,
      isPregnant: emp.isPregnant,
      isInMedicalPeriod: emp.isInMedicalPeriod,
      isWorkInjured: emp.isWorkInjured,
      city: emp.city,
    }
  })

  return { items, total, page, pageSize, totalPages: Math.ceil(total / pageSize) }
}

export async function getEmployeeDetail(orgId: string, id: string) {
  const employee = await prisma.employee.findFirst({
    where: { id, orgId },
    include: {
      contracts: { orderBy: { createdAt: 'desc' } },
      riskItems: { where: { status: 'PENDING' }, orderBy: { level: 'asc' } },
    },
  })

  if (!employee) {
    throw { code: 'NOT_FOUND', message: '员工不存在' }
  }

  let decryptedSalary = 0
  try {
    decryptedSalary = Number(decrypt(employee.monthlySalary)) || 0
  } catch {
    decryptedSalary = Number(employee.monthlySalary) || 0
  }

  return {
    ...employee,
    monthlySalary: decryptedSalary,
    baseSalary: employee.baseSalary ? safeDecryptNum(employee.baseSalary) : null,
    performanceSalary: employee.performanceSalary ? safeDecryptNum(employee.performanceSalary) : null,
  }
}

export async function createEmployee(orgId: string, userId: string, data: any) {
  // 证件号码有效性校验
  if (data.idCardNumber) {
    const idCardError = validateIdCard(data.idCardNumber)
    if (idCardError) {
      throw { code: 'VALIDATION_ERROR', message: idCardError }
    }
    // 童工阻断
    const age = getAgeFromIdCard(data.idCardNumber)
    if (age !== null && age < 16) {
      throw { code: 'VALIDATION_ERROR', message: `该员工年龄 ${age} 岁，未满16周岁，禁止招用童工（《劳动法》第15条）` }
    }
    // 证件号码查重
    const existing = await prisma.employee.findFirst({
      where: { orgId, idCardHash: sha256(data.idCardNumber) },
      select: { id: true, name: true, department: true, status: true },
    })
    if (existing) {
      throw { code: 'DUPLICATE_ID_CARD', message: `证件号码已存在：${existing.name}（${existing.department}，${existing.status === 'ACTIVE' ? '在职' : '离职'}），请确认是否重复录入` }
    }
  }
  // 超龄人员不得签订劳动合同（FIXED/UNFIXED）
  if (data.idCardNumber && data.contract && data.contract.contractType) {
    const overage = isOverageEmployee(data.idCardNumber, data.gender, data.femaleWorkerType)
    if (overage && ['FIXED', 'UNFIXED'].includes(data.contract.contractType)) {
      throw { code: 'VALIDATION_ERROR', message: '超龄人员（达法定退休年龄）不可签订劳动合同，请选择劳务协议或实习协议' }
    }
  }
  // 手机号查重（同组织内不允许重复，影响员工端登录）
  if (data.phone) {
    const phoneExists = await prisma.employee.findFirst({
      where: { orgId, phone: data.phone },
      select: { id: true, name: true, department: true, status: true },
    })
    if (phoneExists) {
      throw { code: 'DUPLICATE_PHONE', message: `手机号已存在：${phoneExists.name}（${phoneExists.department}，${phoneExists.status === 'ACTIVE' ? '在职' : '离职'}），员工端登录需手机号唯一，请确认是否重复录入` }
    }
  }

  const org = await prisma.organization.findUnique({ where: { id: orgId } })
  if (org && org.maxEmployees > 0) {
    const activeCount = await prisma.employee.count({ where: { orgId, status: 'ACTIVE' } })
    if (activeCount >= org.maxEmployees) {
      throw { code: 'PLAN_LIMIT', message: `当前套餐人数上限为 ${org.maxEmployees} 人，已达上限，请升级套餐` }
    }
  }

  const hireDate = new Date(data.hireDate)
  const hireMonth = dateToMonth(hireDate)
  const salaryNum = Number(data.monthlySalary) || 0
  // 工资结构：基本工资 + 绩效工资 = 月薪总额
  const baseSalaryNum = Number(data.baseSalary) || 0
  const performanceSalaryNum = Number(data.performanceSalary) || 0
  const city = data.city || '北京'
  // 劳务协议/实习协议：不缴纳社保公积金，基数强制 0
  const isNoSocialContract = data.contract && ['LABOR', 'INTERNSHIP'].includes(data.contract.contractType)
  const rawSocialInsBase = isNoSocialContract ? 0 : (data.socialInsBase != null ? Number(data.socialInsBase) : salaryNum)
  const rawHousingFundBase = isNoSocialContract ? 0 : (data.housingFundBase != null ? Number(data.housingFundBase) : salaryNum)
  const socialInsBase = isNoSocialContract ? 0 : await clampSocialInsBase(orgId, rawSocialInsBase, city, data.socialAccountId)
  const housingFundBase = isNoSocialContract ? 0 : await clampHousingFundBase(orgId, rawHousingFundBase, city, data.housingAccountId)
  const socialInsStartMonth = isNoSocialContract ? '' : (data.socialInsStartMonth || hireMonth)
  const housingFundStartMonth = isNoSocialContract ? '' : (data.housingFundStartMonth || hireMonth)

  const employee = await prisma.$transaction(async (tx) => {
    // 默认密码：手机号后6位（员工可在员工端自行修改）
    const defaultPassword = data.phone ? data.phone.slice(-6) : '123456'
    const passwordHash = await bcrypt.hash(defaultPassword, 10)
    // 查找该组织的第一个班次作为默认排班（长期=工作日班次）
    const firstShift = await tx.shift.findFirst({ where: { orgId }, orderBy: { createdAt: 'asc' } })
    const emp = await tx.employee.create({
      data: {
        orgId,
        name: data.name,
        department: data.department,
        hireDate,
        monthlySalary: encrypt(data.monthlySalary),
        baseSalary: encrypt(String(baseSalaryNum)),
        performanceSalary: encrypt(String(performanceSalaryNum)),
        gender: data.gender || (data.idCardNumber ? extractGenderFromIdCard(data.idCardNumber) : null),
        femaleWorkerType: data.femaleWorkerType,
        phone: data.phone,
        passwordHash,
        idCardNumber: data.idCardNumber ? encrypt(data.idCardNumber) : null,
        idCardHash: data.idCardNumber ? sha256(data.idCardNumber) : null,
        birthDate: data.idCardNumber ? extractBirthDateFromIdCard(data.idCardNumber) : null,
        isPregnant: data.isPregnant || false,
        isInMedicalPeriod: data.isInMedicalPeriod || false,
        isWorkInjured: data.isWorkInjured || false,
        defaultShiftId: firstShift?.id || null,
        socialInsBase,
        housingFundBase,
        socialInsStartMonth,
        housingFundStartMonth,
        createdBy: userId,
        city: data.city || '北京',
        education: data.education || null,
        position: data.position || null,
        status: data.status || 'ACTIVE',
        supplementaryHousingAccountId: data.supplementaryHousingAccountId || null,
      },
    })

    // 社保公积金记录不在录入时创建，由 HR 在社保模块办理增员后创建
    // 录入时仅保存社保基数到 Employee 表，工资计算直接用 employee.socialInsBase

    await tx.salaryChangeRecord.create({
      data: {
        orgId,
        employeeId: emp.id,
        oldSalary: 0,
        newSalary: salaryNum,
        effectiveDate: hireDate,
        effectiveMonth: hireMonth,
        endMonth: null,
        changeType: 'ONBOARDING',
        createdBy: userId,
      },
    })

    await tx.employeeDepartmentRecord.create({
      data: {
        orgId,
        employeeId: emp.id,
        oldDepartment: '',
        newDepartment: data.department,
        effectiveMonth: hireMonth,
        endMonth: null,
        changeType: 'ONBOARDING',
        createdBy: userId,
      },
    })

    if (data.contract && data.contract.contractType !== 'UNSIGNED') {
      const contractMonths = data.contract.endDate
        ? Math.ceil(daysBetween(new Date(data.contract.endDate), new Date(data.contract.startDate)) / 30.44)
        : data.contract.contractYears * 12

      const probationCheck = validateProbation(contractMonths, data.contract.probationMonths)
      if (!probationCheck.valid) {
        throw { code: 'VALIDATION_ERROR', message: probationCheck.message }
      }

      await tx.laborContract.create({
        data: {
          orgId,
          employeeId: emp.id,
          signDate: data.contract.signDate ? new Date(data.contract.signDate) : null,
          startDate: new Date(data.contract.startDate),
          endDate: data.contract.endDate ? new Date(data.contract.endDate) : null,
          contractType: data.contract.contractType,
          signMethod: data.contract.signMethod || 'PAPER',
          contractYears: data.contract.contractYears || 3,
          probationMonths: data.contract.probationMonths || 0,
          probationSalary: data.contract.probationSalary || 0,
          baseSalary: baseSalaryNum,
          performanceSalary: performanceSalaryNum,
          createdBy: userId,
        },
      })
    }

    return emp
  })

  await runRiskDetection(orgId)

  return { id: employee.id }
}

// 重新入职：复用已有员工基本信息，更新入职日期和状态，可选创建新合同
export async function rehireEmployee(orgId: string, userId: string, id: string, data: any) {
  const employee = await prisma.employee.findFirst({
    where: { id, orgId },
    include: { terminations: { orderBy: { terminationDate: 'desc' }, take: 1 } },
  })
  if (!employee) {
    throw { code: 'NOT_FOUND', message: '员工不存在' }
  }

  const today = new Date()
  today.setHours(0, 0, 0, 0)
  const isResigned = employee.terminations.some((t) => t.status === 'COMPLETED' && t.terminationDate <= today)
  if (!isResigned) {
    throw { code: 'CONFLICT', message: '该员工当前在职，无需重新入职' }
  }

  const newHireDate = new Date(data.hireDate)
  const latestTerm = employee.terminations[0]
  if (latestTerm && newHireDate <= latestTerm.terminationDate) {
    throw { code: 'VALIDATION_ERROR', message: '新入职日期必须晚于上次离职/解聘日期' }
  }

  const newHireMonth = dateToMonth(newHireDate)
  const salaryNum = Number(decrypt(employee.monthlySalary)) || 0
  // 重新入职时支持更新工资结构
  const baseSalaryNum = data.baseSalary != null ? Number(data.baseSalary) : (employee.baseSalary ? Number(decrypt(employee.baseSalary)) || 0 : 0)
  const performanceSalaryNum = data.performanceSalary != null ? Number(data.performanceSalary) : (employee.performanceSalary ? Number(decrypt(employee.performanceSalary)) || 0 : 0)
  const newMonthlySalary = data.baseSalary != null ? baseSalaryNum + performanceSalaryNum : salaryNum
  const city = data.city || employee.city || '北京'
  // 劳务协议/实习协议：不缴纳社保公积金
  const isNoSocialContract = data.contract && ['LABOR', 'INTERNSHIP'].includes(data.contract.contractType)
  const rawSocialInsBase = isNoSocialContract ? 0 : (data.socialInsBase != null ? Number(data.socialInsBase) : salaryNum)
  const rawHousingFundBase = isNoSocialContract ? 0 : (data.housingFundBase != null ? Number(data.housingFundBase) : salaryNum)
  const socialInsBase = isNoSocialContract ? 0 : await clampSocialInsBase(orgId, rawSocialInsBase, city)
  const housingFundBase = isNoSocialContract ? 0 : await clampHousingFundBase(orgId, rawHousingFundBase, city)
  const socialInsStartMonth = isNoSocialContract ? '' : (data.socialInsStartMonth || newHireMonth)
  const housingFundStartMonth = isNoSocialContract ? '' : (data.housingFundStartMonth || newHireMonth)
  const prevHireMonth = prevMonth(newHireMonth)

  // 关闭旧社保缴费记录
  await prisma.employeeSocialInsRecord.updateMany({
    where: { employeeId: id, endMonth: null },
    data: { endMonth: prevHireMonth },
  })

  // 关闭旧公积金缴费记录
  await prisma.employeeHousingFundRecord.updateMany({
    where: { employeeId: id, endMonth: null },
    data: { endMonth: prevHireMonth },
  })

  // 关闭旧薪资记录
  await prisma.salaryChangeRecord.updateMany({
    where: { employeeId: id, endMonth: null },
    data: { endMonth: prevHireMonth },
  })

  // 关闭旧部门记录
  await prisma.employeeDepartmentRecord.updateMany({
    where: { employeeId: id, endMonth: null },
    data: { endMonth: prevHireMonth },
  })

  await prisma.employee.update({
    where: { id },
    data: {
      hireDate: newHireDate,
      status: 'ACTIVE',
      department: data.department || employee.department,
      isPregnant: false,
      isInMedicalPeriod: false,
      isWorkInjured: false,
      socialInsBase,
      housingFundBase,
      socialInsStartMonth,
      socialInsEndMonth: null,
      housingFundStartMonth,
      housingFundEndMonth: null,
      city: data.city || employee.city || '北京',
      // 更新工资结构
      ...(data.baseSalary != null ? {
        monthlySalary: encrypt(String(newMonthlySalary)),
        baseSalary: encrypt(String(baseSalaryNum)),
        performanceSalary: encrypt(String(performanceSalaryNum)),
      } : {}),
    },
  })

  // 社保公积金记录不在重新入职时创建，由 HR 在社保模块办理增员后创建

  // 创建新薪资记录
  await prisma.salaryChangeRecord.create({
    data: {
      orgId,
      employeeId: id,
      oldSalary: salaryNum,
      newSalary: salaryNum,
      effectiveDate: newHireDate,
      effectiveMonth: newHireMonth,
      endMonth: null,
      changeType: 'REHIRE',
      createdBy: userId,
    },
  })

  // 创建新部门记录
  await prisma.employeeDepartmentRecord.create({
    data: {
      orgId,
      employeeId: id,
      oldDepartment: employee.department,
      newDepartment: data.department || employee.department,
      effectiveMonth: newHireMonth,
      endMonth: null,
      changeType: 'REHIRE',
      createdBy: userId,
    },
  })

  if (data.contract && data.contract.contractType !== 'UNSIGNED') {
    const contractMonths = data.contract.endDate
      ? Math.ceil(daysBetween(new Date(data.contract.endDate), new Date(data.contract.startDate)) / 30.44)
      : data.contract.contractYears * 12

    const probationCheck = validateProbation(contractMonths, data.contract.probationMonths)
    if (!probationCheck.valid) {
      throw { code: 'VALIDATION_ERROR', message: probationCheck.message }
    }

    await prisma.laborContract.create({
      data: {
        orgId,
        employeeId: id,
        signDate: data.contract.signDate ? new Date(data.contract.signDate) : null,
        startDate: new Date(data.contract.startDate),
        endDate: data.contract.endDate ? new Date(data.contract.endDate) : null,
        contractType: data.contract.contractType,
        signMethod: data.contract.signMethod || 'PAPER',
        contractYears: data.contract.contractYears || 3,
        probationMonths: data.contract.probationMonths || 0,
        probationSalary: data.contract.probationSalary || 0,
        baseSalary: baseSalaryNum,
        performanceSalary: performanceSalaryNum,
        createdBy: userId,
      },
    })
  }

  await runRiskDetection(orgId)

  return { id }
}

export async function updateEmployee(orgId: string, id: string, data: any) {
  const employee = await prisma.employee.findFirst({ where: { id, orgId } })
  if (!employee) {
    throw { code: 'NOT_FOUND', message: '员工不存在' }
  }

  // 手机号查重（同组织内排除自身，phone 唯一影响员工端登录）
  if (data.phone !== undefined && data.phone) {
    const phoneExists = await prisma.employee.findFirst({
      where: { orgId, phone: data.phone, NOT: { id } },
      select: { id: true, name: true, department: true, status: true },
    })
    if (phoneExists) {
      throw { code: 'DUPLICATE_PHONE', message: `手机号已存在：${phoneExists.name}（${phoneExists.department}），同企业内手机号不可重复` }
    }
  }
  // 身份证查重（同组织内排除自身）
  if (data.idCardNumber !== undefined && data.idCardNumber) {
    const idCardExists = await prisma.employee.findFirst({
      where: { orgId, idCardHash: sha256(data.idCardNumber), NOT: { id } },
      select: { id: true, name: true, department: true, status: true },
    })
    if (idCardExists) {
      throw { code: 'DUPLICATE_ID_CARD', message: `证件号码已存在：${idCardExists.name}（${idCardExists.department}），同企业内身份证号不可重复` }
    }
  }

  const updateData: any = {}
  if (data.name !== undefined) updateData.name = data.name
  if (data.department !== undefined) updateData.department = data.department
  if (data.hireDate !== undefined) updateData.hireDate = new Date(data.hireDate)
  if (data.baseSalary !== undefined || data.performanceSalary !== undefined) {
    const oldSalary = Number(decrypt(employee.monthlySalary)) || 0
    // monthlySalary 始终由 baseSalary + performanceSalary 计算
    const baseNum = data.baseSalary !== undefined ? Number(data.baseSalary) || 0
      : (employee.baseSalary ? Number(decrypt(employee.baseSalary)) || 0 : 0)
    const perfNum = data.performanceSalary !== undefined ? Number(data.performanceSalary) || 0
      : (employee.performanceSalary ? Number(decrypt(employee.performanceSalary)) || 0 : 0)
    const newSalary = baseNum + perfNum
    updateData.monthlySalary = encrypt(String(newSalary))
    if (data.baseSalary !== undefined) updateData.baseSalary = encrypt(String(baseNum))
    if (data.performanceSalary !== undefined) updateData.performanceSalary = encrypt(String(perfNum))
    // 记录薪资变更
    if (oldSalary !== newSalary) {
      const now = new Date()
      const nowMonth = dateToMonth(now)
      // 关闭之前有效记录
      await prisma.salaryChangeRecord.updateMany({
        where: { employeeId: id, endMonth: null },
        data: { endMonth: prevMonth(nowMonth) },
      })
      await prisma.salaryChangeRecord.create({
        data: {
          orgId,
          employeeId: id,
          oldSalary,
          newSalary,
          effectiveDate: now,
          effectiveMonth: nowMonth,
          endMonth: null,
          changeType: 'SALARY_CHANGE',
          reason: data.salaryChangeReason || '手动调整',
          createdBy: '',
        },
      })
    }
  }
  if (data.gender !== undefined) updateData.gender = data.gender
  if (data.femaleWorkerType !== undefined) updateData.femaleWorkerType = data.femaleWorkerType
  if (data.phone !== undefined) updateData.phone = data.phone
  if (data.idCardNumber !== undefined) {
    updateData.idCardNumber = encrypt(data.idCardNumber)
    updateData.idCardHash = sha256(data.idCardNumber)
    updateData.birthDate = extractBirthDateFromIdCard(data.idCardNumber)
    if (!updateData.gender) {
      const gender = extractGenderFromIdCard(data.idCardNumber)
      if (gender) updateData.gender = gender
    }
  }
  if (data.bankName !== undefined) updateData.bankName = data.bankName
  if (data.bankAccount !== undefined) updateData.bankAccount = encrypt(data.bankAccount)
  if (data.emergencyContact !== undefined) updateData.emergencyContact = data.emergencyContact
  if (data.emergencyPhone !== undefined) updateData.emergencyPhone = data.emergencyPhone
  if (data.address !== undefined) updateData.address = data.address
  if (data.isPregnant !== undefined) updateData.isPregnant = data.isPregnant
  if (data.isInMedicalPeriod !== undefined) updateData.isInMedicalPeriod = data.isInMedicalPeriod
  if (data.isWorkInjured !== undefined) updateData.isWorkInjured = data.isWorkInjured
  if (data.socialInsBase !== undefined) {
    const city = data.city || employee.city || '北京'
    // 查询最新合同类型，劳务/实习协议强制基数为0
    const latestContract = await prisma.laborContract.findFirst({
      where: { employeeId: id },
      orderBy: { createdAt: 'desc' },
      select: { contractType: true },
    })
    const isNoSocial = latestContract && ['LABOR', 'INTERNSHIP'].includes(latestContract.contractType)
    if (isNoSocial) {
      updateData.socialInsBase = 0
      // 关闭在保社保记录
      const nowMonth = new Date().toISOString().slice(0, 7)
      await prisma.employeeSocialInsRecord.updateMany({
        where: { employeeId: id, endMonth: null },
        data: { endMonth: nowMonth, changeType: 'TERMINATION' },
      })
    } else {
      updateData.socialInsBase = await clampSocialInsBase(orgId, Number(data.socialInsBase), city)
    }
  }
  if (data.housingFundBase !== undefined) {
    const city = data.city || employee.city || '北京'
    const latestContract = await prisma.laborContract.findFirst({
      where: { employeeId: id },
      orderBy: { createdAt: 'desc' },
      select: { contractType: true },
    })
    const isNoSocial = latestContract && ['LABOR', 'INTERNSHIP'].includes(latestContract.contractType)
    if (isNoSocial) {
      updateData.housingFundBase = 0
      const nowMonth = new Date().toISOString().slice(0, 7)
      await prisma.employeeHousingFundRecord.updateMany({
        where: { employeeId: id, endMonth: null },
        data: { endMonth: nowMonth, changeType: 'TERMINATION' },
      })
    } else {
      updateData.housingFundBase = await clampHousingFundBase(orgId, Number(data.housingFundBase), city)
    }
  }
  if (data.specialDeduction !== undefined) updateData.specialDeduction = data.specialDeduction
  if (data.city !== undefined) updateData.city = data.city
  if (data.education !== undefined) updateData.education = data.education
  if (data.position !== undefined) updateData.position = data.position
  if (data.status !== undefined) updateData.status = data.status
  if (data.supplementaryHousingAccountId !== undefined) updateData.supplementaryHousingAccountId = data.supplementaryHousingAccountId || null

  // 参保城市变更：关闭旧城市在保记录，创建新城市记录
  if (data.city !== undefined && data.city !== employee.city) {
    const nowMonth = new Date().toISOString().slice(0, 7)
    const cityChangeReason = data.cityChangeReason || '未填写原因'
    const changeRemark = `城市变更：${employee.city || '未设置'} → ${data.city}（${cityChangeReason}）`
    // 社保：关闭旧在保记录，创建新城市记录
    const activeSocial = await prisma.employeeSocialInsRecord.findFirst({
      where: { employeeId: id, endMonth: null },
    })
    if (activeSocial) {
      await prisma.employeeSocialInsRecord.update({
        where: { id: activeSocial.id },
        data: { endMonth: nowMonth, changeType: 'CITY_CHANGE', remark: changeRemark },
      })
      await prisma.employeeSocialInsRecord.create({
        data: {
          orgId,
          employeeId: id,
          city: data.city,
          startMonth: nowMonth,
          endMonth: null,
          base: activeSocial.base,
          changeType: 'CITY_CHANGE',
          remark: changeRemark,
          createdBy: '',
        },
      })
    } else {
      // 兜底：没有在保记录也创建一条，保留变更历史
      await prisma.employeeSocialInsRecord.create({
        data: {
          orgId,
          employeeId: id,
          city: data.city,
          startMonth: nowMonth,
          endMonth: null,
          base: employee.socialInsBase || 0,
          changeType: 'CITY_CHANGE',
          remark: changeRemark,
          createdBy: '',
        },
      })
    }
    // 公积金：同上
    const activeHousing = await prisma.employeeHousingFundRecord.findFirst({
      where: { employeeId: id, endMonth: null },
    })
    if (activeHousing) {
      await prisma.employeeHousingFundRecord.update({
        where: { id: activeHousing.id },
        data: { endMonth: nowMonth, changeType: 'CITY_CHANGE', remark: changeRemark },
      })
      await prisma.employeeHousingFundRecord.create({
        data: {
          orgId,
          employeeId: id,
          city: data.city,
          startMonth: nowMonth,
          endMonth: null,
          base: activeHousing.base,
          changeType: 'CITY_CHANGE',
          remark: changeRemark,
          createdBy: '',
        },
      })
    } else {
      // 兜底：没有在保记录也创建一条
      await prisma.employeeHousingFundRecord.create({
        data: {
          orgId,
          employeeId: id,
          city: data.city,
          startMonth: nowMonth,
          endMonth: null,
          base: employee.housingFundBase || 0,
          changeType: 'CITY_CHANGE',
          remark: changeRemark,
          createdBy: '',
        },
      })
    }
    // 写审计日志
    await prisma.auditLog.create({
      data: {
        orgId,
        userId: '',
        action: 'CITY_CHANGE',
        entity: 'Employee',
        entityId: id,
        detail: { oldCity: employee.city, newCity: data.city, reason: cityChangeReason, remark: changeRemark },
      },
    })
  }

  await prisma.employee.update({ where: { id }, data: updateData })
  await runRiskDetection(orgId)

  return { id }
}

export async function deleteEmployee(orgId: string, id: string) {
  const employee = await prisma.employee.findFirst({ where: { id, orgId } })
  if (!employee) {
    throw { code: 'NOT_FOUND', message: '员工不存在' }
  }

  await prisma.employee.update({ where: { id }, data: { status: 'RESIGNED' } })
  await prisma.riskItem.updateMany({
    where: { employeeId: id, status: 'PENDING' },
    data: { status: 'RESOLVED', resolvedAt: new Date() },
  })

  return { id }
}

export async function batchRenew(orgId: string, userId: string, contractIds: string[], years: number) {
  const contracts = await prisma.laborContract.findMany({
    where: { id: { in: contractIds }, orgId },
  })

  if (contracts.length === 0) {
    throw { code: 'NOT_FOUND', message: '未找到符合条件的合同' }
  }

  for (const contract of contracts) {
    const newStartDate = contract.endDate || new Date()
    const newEndDate = new Date(newStartDate)
    newEndDate.setFullYear(newEndDate.getFullYear() + years)

    // 将旧合同 endDate 截止到续签开始日前一天，避免重叠
    const oldEndDate = new Date(newStartDate)
    oldEndDate.setDate(oldEndDate.getDate() - 1)

    await prisma.laborContract.update({
      where: { id: contract.id },
      data: { endDate: oldEndDate },
    })

    await prisma.laborContract.create({
      data: {
        orgId,
        employeeId: contract.employeeId,
        signDate: new Date(),
        startDate: newStartDate,
        endDate: newEndDate,
        contractType: contract.contractType,
        signMethod: contract.signMethod,
        contractYears: years,
        probationMonths: 0,
        probationSalary: 0,
        baseSalary: contract.baseSalary || 0,
        performanceSalary: contract.performanceSalary || 0,
        renewalCount: contract.renewalCount + 1,
        createdBy: userId,
      },
    })
  }

  await runRiskDetection(orgId)

  return { renewed: contracts.length }
}

export async function addContract(orgId: string, userId: string, data: any) {
  const employee = await prisma.employee.findFirst({ where: { id: data.employeeId, orgId } })
  if (!employee) {
    throw { code: 'NOT_FOUND', message: '员工不存在' }
  }

  // 检查是否存在日期完全相同的合同，防止重复提交
  const duplicate = await prisma.laborContract.findFirst({
    where: {
      employeeId: data.employeeId,
      orgId,
      startDate: new Date(data.startDate),
      ...(data.endDate ? { endDate: new Date(data.endDate) } : { endDate: null }),
    },
  })
  if (duplicate) {
    throw { code: 'DUPLICATE', message: '该员工已存在相同日期的合同，请勿重复添加' }
  }

  // 工资结构：baseSalary 为 0 时，用员工档案月工资填充
  let contractBase = Number(data.baseSalary) || 0
  let contractPerf = Number(data.performanceSalary) || 0
  if (contractBase === 0 && contractPerf === 0) {
    const emp = await prisma.employee.findFirst({
      where: { id: data.employeeId, orgId },
      select: { monthlySalary: true, baseSalary: true, performanceSalary: true },
    })
    if (emp) {
      try {
        contractBase = emp.baseSalary ? Number(decrypt(emp.baseSalary)) || 0 : 0
        contractPerf = emp.performanceSalary ? Number(decrypt(emp.performanceSalary)) || 0 : 0
      } catch {}
      if (contractBase === 0 && contractPerf === 0) {
        try { contractBase = Number(decrypt(emp.monthlySalary)) || 0 } catch {}
      }
    }
  }

  const contractMonths = data.endDate
    ? Math.ceil(daysBetween(new Date(data.endDate), new Date(data.startDate)) / 30.44)
    : data.contractYears * 12

  const probationCheck = validateProbation(contractMonths, data.probationMonths)
  if (!probationCheck.valid) {
    throw { code: 'VALIDATION_ERROR', message: probationCheck.message }
  }

  const contract = await prisma.laborContract.create({
    data: {
      orgId,
      employeeId: data.employeeId,
      signDate: data.signDate ? new Date(data.signDate) : null,
      startDate: new Date(data.startDate),
      endDate: data.endDate ? new Date(data.endDate) : null,
      contractType: data.contractType,
      signMethod: data.signMethod || 'PAPER',
      contractYears: data.contractYears || 3,
      probationMonths: data.probationMonths || 0,
      probationSalary: data.probationSalary || 0,
      baseSalary: contractBase,
      performanceSalary: contractPerf,
      attachmentName: data.attachmentUrl ? '合同扫描件' : null,
      attachmentUrl: data.attachmentUrl || null,
      electronicContractNo: data.electronicContractNo || null,
      electronicContractUrl: data.electronicContractUrl || null,
      createdBy: userId,
    },
  })

  await runRiskDetection(orgId)

  return { id: contract.id }
}
