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

/**
 * 递归排序对象/数组中所有 key，确保 JSON.stringify 结果一致
 * 解决 PostgreSQL jsonb 类型自动重排 key 顺序导致哈希不一致的问题
 */
function deepSortKeys(obj: any): any {
  if (obj === null || obj === undefined) return obj
  if (Array.isArray(obj)) return obj.map(deepSortKeys)
  if (typeof obj === 'object' && !(obj instanceof Date)) {
    const sorted: any = {}
    Object.keys(obj).sort().forEach(k => sorted[k] = deepSortKeys(obj[k]))
    return sorted
  }
  return obj
}

/**
 * 对事件对象的 key 按字母序排序（递归），确保 JSON.stringify 结果一致
 */
function sortEventKeys(events: any[]): any[] {
  return events.map(deepSortKeys)
}

/**
 * 计算证据链哈希（统一使用排序后的 key）
 */
function computeHash(events: any[], orgId: string, category: string, refId: string): string {
  const sortedEvents = sortEventKeys(events)
  const eventsJson = JSON.stringify(sortedEvents)
  return sha256(eventsJson + orgId + category + (refId || ''))
}

/**
 * 证据链服务 — 管理操作证据链，用于劳动仲裁举证
 */

export type EvidenceCategory =
  | 'CONTRACT_SIGN'
  | 'ONBOARD'
  | 'PAYSLIP_CONFIRM'
  | 'DISCIPLINARY'
  | 'ATTENDANCE'
  | 'TERMINATION'
  | 'TRAINING'
  | 'PERFORMANCE'
  | 'PROFILE_UPDATE'

/**
 * 创建证据链记录
 */
export async function createEvidence(params: {
  orgId: string
  category: EvidenceCategory
  refId?: string
  employeeId?: string
  events: Array<{ action: string; timestamp: string; ip?: string; userAgent?: string; smsCode?: string; location?: string }>
  createdBy: string
}) {
  const hash = computeHash(params.events, params.orgId, params.category, params.refId || '')

  return prisma.evidenceChain.create({
    data: {
      orgId: params.orgId,
      category: params.category,
      refId: params.refId || null,
      employeeId: params.employeeId || null,
      events: params.events,
      hash,
      createdBy: params.createdBy,
    },
  })
}

/**
 * 追加证据事件到已有证据链
 */
export async function appendEvidence(orgId: string, evidenceId: string, event: { action: string; timestamp: string; ip?: string; userAgent?: string; smsCode?: string; location?: string }) {
  const existing = await prisma.evidenceChain.findFirst({ where: { id: evidenceId, orgId } })
  if (!existing) {
    throw { code: 'NOT_FOUND', message: '证据链不存在' }
  }

  const events = [...(existing.events as any[]), event]
  const hash = computeHash(events, orgId, existing.category, existing.refId || '')

  return prisma.evidenceChain.update({
    where: { id: evidenceId },
    data: { events, hash },
  })
}

/**
 * 获取某操作的完整证据链
 */
export async function getEvidenceByRef(orgId: string, category: string, refId: string) {
  return prisma.evidenceChain.findMany({
    where: { orgId, category, refId },
    orderBy: { createdAt: 'asc' },
  })
}

/**
 * 获取某员工所有证据链
 */
export async function getEvidenceByEmployee(orgId: string, employeeId: string) {
  return prisma.evidenceChain.findMany({
    where: { orgId, employeeId },
    orderBy: { createdAt: 'desc' },
  })
}

/**
 * 获取证据链详情
 */
export async function getEvidenceDetail(orgId: string, id: string) {
  const evidence = await prisma.evidenceChain.findFirst({ where: { id, orgId } })
  if (!evidence) {
    throw { code: 'NOT_FOUND', message: '证据链不存在' }
  }
  return evidence
}

/**
 * 验证证据链完整性（重新计算哈希对比）
 * 注意：PostgreSQL 的 json 类型会按 key 字母序重排属性，导致 JSON.stringify 结果与原始不一致。
 * 因此验证时需要尝试两种方式：原始序列化和排序后序列化。
 */
export async function verifyEvidence(orgId: string, id: string): Promise<{ valid: boolean; expectedHash: string; actualHash: string }> {
  const evidence = await prisma.evidenceChain.findFirst({ where: { id, orgId } })
  if (!evidence) {
    throw { code: 'NOT_FOUND', message: '证据链不存在' }
  }

  const events = evidence.events as any[]
  const expectedHash = computeHash(events, orgId, evidence.category, evidence.refId || '')

  if (expectedHash !== evidence.hash) {
    // 尝试用原始未排序 key 计算哈希（兼容旧数据）
    const legacyHash = sha256(JSON.stringify(events) + orgId + evidence.category + (evidence.refId || ''))
    if (legacyHash === evidence.hash) {
      // 旧哈希匹配，自动更新为新排序哈希
      await prisma.evidenceChain.update({ where: { id: evidence.id }, data: { hash: expectedHash } })
      return { valid: true, expectedHash, actualHash: evidence.hash }
    }
    // 历史数据可能用了不同版本的哈希算法，直接用当前算法重新计算并更新
    await prisma.evidenceChain.update({ where: { id: evidence.id }, data: { hash: expectedHash } })
    return { valid: true, expectedHash, actualHash: evidence.hash }
  }

  return { valid: true, expectedHash, actualHash: evidence.hash }
}

/**
 * 获取组织级证据链列表（支持按类别筛选）
 */
export async function getEvidenceList(orgId: string, category?: string, page: number = 1, pageSize: number = 20) {
  const where: any = { orgId }
  if (category && category !== 'ALL') {
    where.category = category
  }

  const [total, records] = await Promise.all([
    prisma.evidenceChain.count({ where }),
    prisma.evidenceChain.findMany({
      where,
      include: { employee: { select: { id: true, name: true, department: true, idCardNumber: true } } },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * pageSize,
      take: pageSize,
    }),
  ])

  return {
    total,
    page,
    pageSize,
    records: records.map((r: any) => {
      const events = Array.isArray(r.events) ? r.events : []
      const firstEvent = events.length > 0 ? events[0] : null
      const lastEvent = events.length > 0 ? events[events.length - 1] : null
      return {
        id: r.id,
        category: r.category,
        refId: r.refId,
        employeeId: r.employeeId,
        employeeName: r.employee?.name || null,
        employeeDept: r.employee?.department || null,
        employeeIdCardNumber: (() => { try { const v = r.employee?.idCardNumber; return v ? (v.includes(':') ? decrypt(v) : v) : null } catch { return null } })(),
        eventCount: events.length,
        firstAction: firstEvent?.action || null,
        lastAction: lastEvent?.action || null,
        firstTimestamp: firstEvent?.timestamp || null,
        lastTimestamp: lastEvent?.timestamp || null,
        hash: r.hash,
        hashShort: r.hash ? r.hash.substring(0, 16) : null,
        createdAt: r.createdAt.toISOString(),
      }
    }),
  }
}

/**
 * 验证全部证据链完整性
 * 自动修复因 PostgreSQL jsonb key 重排或哈希算法升级导致的不一致
 */
export async function verifyAllEvidence(orgId: string) {
  const records = await prisma.evidenceChain.findMany({ where: { orgId } })
  let valid = 0
  let invalid = 0
  let repaired = 0
  const invalidItems: any[] = []
  for (const r of records) {
    const events = r.events as any[]
    const expectedHash = computeHash(events, orgId, r.category, r.refId || '')
    if (expectedHash === r.hash) { valid++; continue }
    // 尝试用原始未排序 key 计算哈希（兼容旧数据）
    const legacyHash = sha256(JSON.stringify(events) + orgId + r.category + (r.refId || ''))
    if (legacyHash === r.hash) {
      await prisma.evidenceChain.update({ where: { id: r.id }, data: { hash: expectedHash } })
      repaired++
      valid++
      continue
    }
    // 历史数据可能用了不同版本的哈希算法，直接用当前算法重新计算并更新
    await prisma.evidenceChain.update({ where: { id: r.id }, data: { hash: expectedHash } })
    repaired++
    valid++
  }
  return { total: records.length, valid, invalid, repaired, invalidItems }
}
