import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'

/**
 * 考勤确认服务
 */

/**
 * 创建月度考勤确认记录
 */
export async function createAttendanceConfirmation(orgId: string, userId: string, data: {
  employeeId: string
  month: string
  workDays: number
  weekdayHours: number
  weekendHours: number
  holidayHours: number
  overtimePay: number
}) {
  const existing = await prisma.attendanceConfirmation.findUnique({
    where: { orgId_employeeId_month: { orgId, employeeId: data.employeeId, month: data.month } },
  })
  if (existing) {
    throw { code: 'CONFLICT', message: '该月考勤确认记录已存在' }
  }

  return prisma.attendanceConfirmation.create({
    data: {
      orgId,
      employeeId: data.employeeId,
      month: data.month,
      workDays: data.workDays,
      weekdayHours: data.weekdayHours,
      weekendHours: data.weekendHours,
      holidayHours: data.holidayHours,
      overtimePay: data.overtimePay,
      createdBy: userId,
    },
  })
}

/**
 * 批量创建月度考勤确认记录
 */
export async function batchCreateAttendanceConfirmations(orgId: string, userId: string, month: string, items: Array<{
  employeeId: string
  workDays: number
  weekdayHours: number
  weekendHours: number
  holidayHours: number
  overtimePay: number
  deductionAmount?: number
}>) {
  const results: Array<{ employeeId: string; success: boolean; error?: string }> = []

  for (const item of items) {
    try {
      const existing = await prisma.attendanceConfirmation.findUnique({
        where: { orgId_employeeId_month: { orgId, employeeId: item.employeeId, month } },
      })
      if (existing) {
        // 更新已有记录
        await prisma.attendanceConfirmation.update({
          where: { id: existing.id },
          data: {
            workDays: item.workDays,
            weekdayHours: item.weekdayHours,
            weekendHours: item.weekendHours,
            holidayHours: item.holidayHours,
            overtimePay: item.overtimePay,
            deductionAmount: item.deductionAmount || 0,
            status: 'PENDING',
          },
        })
      } else {
        await prisma.attendanceConfirmation.create({
          data: {
            orgId,
            employeeId: item.employeeId,
            month,
            workDays: item.workDays,
            weekdayHours: item.weekdayHours,
            weekendHours: item.weekendHours,
            holidayHours: item.holidayHours,
            overtimePay: item.overtimePay,
            deductionAmount: item.deductionAmount || 0,
            createdBy: userId,
          },
        })
      }
      results.push({ employeeId: item.employeeId, success: true })
    } catch (err: any) {
      results.push({ employeeId: item.employeeId, success: false, error: err.message })
    }
  }

  return { total: items.length, success: results.filter(r => r.success).length, results }
}

/**
 * 获取月度考勤确认列表
 */
export async function getAttendanceConfirmations(orgId: string, month: string, status?: string, department?: string) {
  const where: any = { orgId, month }
  if (status) where.status = status
  if (department) where.employee = { department }

  return prisma.attendanceConfirmation.findMany({
    where,
    include: { employee: { select: { id: true, name: true, department: true } } },
    orderBy: { employee: { name: 'asc' } },
  })
}

/**
 * 员工确认考勤（员工端）
 */
export async function confirmAttendance(orgId: string, employeeId: string, month: string, ip: string, disputeNote?: string) {
  const record = await prisma.attendanceConfirmation.findUnique({
    where: { orgId_employeeId_month: { orgId, employeeId, month } },
  })
  if (!record) {
    throw { code: 'NOT_FOUND', message: '考勤确认记录不存在' }
  }

  if (disputeNote) {
    // 有异议
    return prisma.attendanceConfirmation.update({
      where: { id: record.id },
      data: { status: 'DISPUTED', disputeNote, confirmIp: ip },
    })
  }

  // 确认无误
  return prisma.attendanceConfirmation.update({
    where: { id: record.id },
    data: { status: 'CONFIRMED', confirmedAt: new Date(), confirmIp: ip },
  })
}

/**
 * 获取考勤确认统计
 */
export async function getAttendanceStats(orgId: string, month: string) {
  const records = await prisma.attendanceConfirmation.findMany({
    where: { orgId, month },
  })

  return {
    total: records.length,
    pending: records.filter(r => r.status === 'PENDING').length,
    confirmed: records.filter(r => r.status === 'CONFIRMED').length,
    disputed: records.filter(r => r.status === 'DISPUTED').length,
  }
}

// ========== 班次管理 ==========

export async function getShifts(orgId: string) {
  return prisma.shift.findMany({
    where: { orgId },
    orderBy: { startTime: 'asc' },
  })
}

export async function createShift(orgId: string, userId: string, data: {
  name: string
  startTime: string
  endTime: string
  flexibleMinutes?: number
  restMinutes?: number
  color?: string
}) {
  return prisma.shift.create({
    data: {
      orgId,
      name: data.name,
      startTime: data.startTime,
      endTime: data.endTime,
      flexibleMinutes: data.flexibleMinutes || 0,
      restMinutes: data.restMinutes || 0,
      color: data.color || '#3b82f6',
      createdBy: userId,
    },
  })
}

export async function updateShift(orgId: string, id: string, data: {
  name?: string
  startTime?: string
  endTime?: string
  flexibleMinutes?: number
  restMinutes?: number
  color?: string
}) {
  return prisma.shift.update({ where: { id }, data })
}

export async function deleteShift(orgId: string, id: string) {
  return prisma.shift.delete({ where: { id } })
}

// ========== 排班管理 ==========

export async function getShiftAssignments(orgId: string, date: string) {
  const day = new Date(date)
  day.setHours(0, 0, 0, 0)
  const nextDay = new Date(day)
  nextDay.setDate(nextDay.getDate() + 1)

  // 查询当天排班记录
  const assignments = await prisma.shiftAssignment.findMany({
    where: { orgId, date: { gte: day, lt: nextDay } },
    include: {
      employee: { select: { id: true, name: true, department: true } },
      shift: true,
    },
    orderBy: { employee: { name: 'asc' } },
  })

  // 查询所有在职员工的默认班次（长期排班）
  const employees = await prisma.employee.findMany({
    where: { orgId, status: 'ACTIVE' },
    select: { id: true, name: true, department: true, idCardNumber: true, defaultShiftId: true, defaultShift: true },
    orderBy: { name: 'asc' },
  })

  // 合并：有当天排班记录的用排班记录，没有的 fallback 到默认班次
  // 如果当天排班和默认班次相同，也标记为 isDefault（视为长期排班）
  const assignmentMap = new Map(assignments.map(a => [a.employeeId, a]))
  const merged = employees.map(emp => {
    // 解密身份证号
    let idCardNumber: string | null = null
    try { idCardNumber = emp.idCardNumber ? (emp.idCardNumber.includes(':') ? decrypt(emp.idCardNumber) : emp.idCardNumber) : null } catch { idCardNumber = null }

    const explicit = assignmentMap.get(emp.id)
    if (explicit) {
      // 当天排班和默认班次相同，视为长期排班
      const sameAsDefault = emp.defaultShiftId && explicit.shiftId === emp.defaultShiftId
      return {
        ...explicit,
        isDefault: !!sameAsDefault,
        employee: { ...explicit.employee, idCardNumber },
      }
    }
    // 没有当天排班，使用默认班次（长期排班）
    if (emp.defaultShift) {
      return {
        id: `default-${emp.id}`,
        employeeId: emp.id,
        shiftId: emp.defaultShiftId,
        shift: emp.defaultShift,
        date: day,
        isDefault: true,
        employee: { id: emp.id, name: emp.name, department: emp.department, idCardNumber },
      }
    }
    // 无排班
    return {
      id: `none-${emp.id}`,
      employeeId: emp.id,
      shiftId: null,
      shift: null,
      date: day,
      isDefault: false,
      employee: { id: emp.id, name: emp.name, department: emp.department, idCardNumber },
    }
  })

  return merged
}

export async function batchAssignShifts(orgId: string, userId: string, items: Array<{
  employeeId: string
  shiftId: string
  date: string
}>) {
  const results: Array<{ employeeId: string; date: string; success: boolean; error?: string }> = []

  for (const item of items) {
    try {
      const date = new Date(item.date)
      date.setHours(0, 0, 0, 0)

      const existing = await prisma.shiftAssignment.findUnique({
        where: { employeeId_date: { employeeId: item.employeeId, date } },
      })

      if (existing) {
        await prisma.shiftAssignment.update({
          where: { id: existing.id },
          data: { shiftId: item.shiftId },
        })
      } else {
        await prisma.shiftAssignment.create({
          data: {
            orgId,
            employeeId: item.employeeId,
            shiftId: item.shiftId,
            date,
            createdBy: userId,
          },
        })
      }
      results.push({ employeeId: item.employeeId, date: item.date, success: true })
    } catch (err: any) {
      results.push({ employeeId: item.employeeId, date: item.date, success: false, error: err.message })
    }
  }

  return { total: items.length, success: results.filter(r => r.success).length, results }
}

export async function deleteShiftAssignment(orgId: string, id: string) {
  return prisma.shiftAssignment.delete({ where: { id } })
}

// ========== 每日出勤 ==========

export async function manualCorrectAttendance(orgId: string, data: {
  employeeId: string
  date: string
  checkInTime?: string
  checkOutTime?: string
  status?: string
  remark?: string
  createdBy?: string
}) {
  const day = new Date(data.date)
  day.setHours(0, 0, 0, 0)
  const nextDay = new Date(day)
  nextDay.setDate(nextDay.getDate() + 1)

  const existing = await prisma.attendanceRecord.findFirst({
    where: { orgId, employeeId: data.employeeId, date: { gte: day, lt: nextDay } },
  })

  const checkInTime = data.checkInTime ? new Date(`${data.date}T${data.checkInTime}:00Z`).toISOString() : null
  const checkOutTime = data.checkOutTime ? new Date(`${data.date}T${data.checkOutTime}:00Z`).toISOString() : null

  let workHours = 0
  if (checkInTime && checkOutTime) {
    workHours = Math.round((new Date(checkOutTime).getTime() - new Date(checkInTime).getTime()) / 3600000 * 100) / 100
  }

  if (existing) {
    return prisma.attendanceRecord.update({
      where: { id: existing.id },
      data: {
        checkInTime,
        checkOutTime,
        status: data.status || 'NORMAL',
        workHours,
        remark: data.remark || existing.remark,
      },
    })
  } else {
    return prisma.attendanceRecord.create({
      data: {
        orgId,
        employeeId: data.employeeId,
        date: day,
        checkInTime,
        checkOutTime,
        status: data.status || 'NORMAL',
        workHours,
        remark: data.remark || null,
        createdBy: data.createdBy || 'system',
      },
    })
  }
}

export async function getDailyAttendance(orgId: string, date: string) {
  const day = new Date(date)
  day.setHours(0, 0, 0, 0)
  const nextDay = new Date(day)
  nextDay.setDate(nextDay.getDate() + 1)

  const [records, assignments, employees] = await Promise.all([
    prisma.attendanceRecord.findMany({
      where: { orgId, date: { gte: day, lt: nextDay } },
    }),
    prisma.shiftAssignment.findMany({
      where: { orgId, date: { gte: day, lt: nextDay } },
      include: { shift: true },
    }),
    prisma.employee.findMany({
      where: { orgId, status: 'ACTIVE' },
      select: { id: true, name: true, department: true, idCardNumber: true, defaultShiftId: true, defaultShift: true },
      orderBy: { name: 'asc' },
    }),
  ])

  const recordMap = new Map(records.map(r => [r.employeeId, r]))
  const shiftMap = new Map(assignments.map(a => [a.employeeId, a.shift]))

  return employees.map(emp => {
    const record = recordMap.get(emp.id)
    // 优先使用当天排班，没有则 fallback 到默认班次
    const shift = shiftMap.get(emp.id) || emp.defaultShift
    // 解密身份证号
    let idCardNumber: string | null = null
    try { idCardNumber = emp.idCardNumber ? (emp.idCardNumber.includes(':') ? decrypt(emp.idCardNumber) : emp.idCardNumber) : null } catch { idCardNumber = null }

    return {
      employeeId: emp.id,
      name: emp.name,
      department: emp.department,
      idCardNumber,
      shift: shift ? { name: shift.name, startTime: shift.startTime, endTime: shift.endTime, color: shift.color } : null,
      checkInTime: record?.checkInTime || null,
      checkOutTime: record?.checkOutTime || null,
      status: record?.status || 'UNREGISTERED',
      lateMinutes: record?.lateMinutes || 0,
      earlyMinutes: record?.earlyMinutes || 0,
      workHours: record?.workHours || 0,
      overtimeHours: record?.overtimeHours || 0,
      remark: record?.remark || null,
    }
  })
}

// ========== 月度出勤报表 ==========

export async function getMonthlyReport(orgId: string, month: string) {
  const monthStart = new Date(month + '-01')
  const monthEnd = new Date(monthStart)
  monthEnd.setMonth(monthEnd.getMonth() + 1)

  const [records, confirmations, overtimes, leaves] = await Promise.all([
    prisma.attendanceRecord.findMany({
      where: { orgId, date: { gte: monthStart, lt: monthEnd } },
    }),
    prisma.attendanceConfirmation.findMany({
      where: { orgId, month },
      include: { employee: { select: { id: true, name: true, department: true } } },
    }),
    prisma.overtimeRecord.findMany({
      where: { orgId, month },
    }),
    prisma.leaveRecord.findMany({
      where: { orgId, startDate: { lt: monthEnd }, endDate: { gte: monthStart } },
    }),
  ])

  const employees = await prisma.employee.findMany({
    where: { orgId, status: 'ACTIVE' },
    select: { id: true, name: true, department: true },
    orderBy: { name: 'asc' },
  })

  const otMap = new Map<string, { hours: number; pay: number }>()
  for (const ot of overtimes) {
    const totalHours = (ot.weekdayHours || 0) + (ot.weekendHours || 0) + (ot.holidayHours || 0)
    const prev = otMap.get(ot.employeeId) || { hours: 0, pay: 0 }
    otMap.set(ot.employeeId, { hours: prev.hours + totalHours, pay: prev.pay + (ot.totalPay || 0) })
  }

  const leaveMap = new Map<string, number>()
  for (const lv of leaves) {
    leaveMap.set(lv.employeeId, (leaveMap.get(lv.employeeId) || 0) + lv.days)
  }

  return employees.map(emp => {
    const empRecords = records.filter(r => r.employeeId === emp.id)
    const confirmation = confirmations.find(c => c.employeeId === emp.id)

    return {
      employeeId: emp.id,
      name: emp.name,
      department: emp.department,
      workDays: confirmation?.workDays || empRecords.filter(r => r.status === 'NORMAL').length,
      lateCount: empRecords.filter(r => r.status === 'LATE').length,
      earlyLeaveCount: empRecords.filter(r => r.status === 'EARLY_LEAVE').length,
      absentDays: empRecords.filter(r => r.status === 'ABSENT').length,
      leaveDays: leaveMap.get(emp.id) || 0,
      overtimeHours: confirmation ? (confirmation.weekdayHours + confirmation.weekendHours + confirmation.holidayHours) : (otMap.get(emp.id)?.hours || 0),
      overtimePay: confirmation?.overtimePay || otMap.get(emp.id)?.pay || 0,
      confirmationStatus: confirmation?.status || null,
    }
  })
}

// ========== 休假记录 ==========

export async function getLeaveRecords(orgId: string, employeeId?: string) {
  const where: any = { orgId }
  if (employeeId) where.employeeId = employeeId

  return prisma.leaveRecord.findMany({
    where,
    include: { employee: { select: { id: true, name: true, department: true } } },
    orderBy: { startDate: 'desc' },
  })
}

export async function createLeaveRecord(orgId: string, userId: string, data: {
  employeeId: string
  leaveType: string
  startDate: string
  endDate: string
  days: number
  reason?: string
  remark?: string
}) {
  return prisma.leaveRecord.create({
    data: {
      orgId,
      employeeId: data.employeeId,
      leaveType: data.leaveType,
      startDate: new Date(data.startDate),
      endDate: new Date(data.endDate),
      days: data.days,
      reason: data.reason || null,
      remark: data.remark || null,
      createdBy: userId,
    },
    include: { employee: { select: { id: true, name: true, department: true } } },
  })
}

export async function deleteLeaveRecord(orgId: string, id: string) {
  return prisma.leaveRecord.delete({ where: { id } })
}
