import crypto from 'node:crypto'

/**
 * affiliate_dash 商户开放接口（/api/client/v1）签名。
 *
 * 请求签名（§3.1）：body 先 sha256，参数按 ASCII 字典序拼接（固定顺序恰好为字典序）：
 *   content = app_key=<appKey>&body_sha256=<sha256hex(body)>&method=<GET|POST>&nonce=<nonce>&path=<path>&timestamp=<unix秒>
 *   X-Sign  = hex(HMAC-SHA256(secret, content))，小写。
 * ⚠️ 参数名是 `app_key`（非旧接口的 `api_key`），且 GET 请求 body 为空串。
 *
 * 回调验签（§3.2）：content = body_sha256=<sha256hex(原始body)>&timestamp=<X-Timestamp>，
 *   secret 为回调 secret（cb_ 开头）。
 */
export function sha256Hex(input: string): string {
  return crypto.createHash('sha256').update(input, 'utf8').digest('hex')
}

export function hmacSha256Hex(secret: string, content: string): string {
  return crypto.createHmac('sha256', secret).update(content, 'utf8').digest('hex').toLowerCase()
}

export function buildClientSign(input: {
  appKey: string
  appSecret: string
  method: string
  path: string
  body: string
  timestamp: string
  nonce: string
}): string {
  const content = [
    `app_key=${input.appKey}`,
    `body_sha256=${sha256Hex(input.body)}`,
    `method=${input.method.toUpperCase()}`,
    `nonce=${input.nonce}`,
    `path=${input.path}`,
    `timestamp=${input.timestamp}`,
  ].join('&')

  return hmacSha256Hex(input.appSecret, content)
}

/** 生成请求所需的 X-Timestamp / X-Nonce / X-Sign（X-App-Key 由调用方放置）。 */
export function createClientSignHeaders(input: {
  appKey: string
  appSecret: string
  method: string
  path: string
  body: string
  timestamp?: string
  nonce?: string
}): {
  'X-App-Key': string
  'X-Timestamp': string
  'X-Nonce': string
  'X-Sign': string
} {
  const timestamp = input.timestamp || String(Math.floor(Date.now() / 1000))
  const nonce = input.nonce || crypto.randomBytes(24).toString('hex')
  const sign = buildClientSign({
    appKey: input.appKey,
    appSecret: input.appSecret,
    method: input.method,
    path: input.path,
    body: input.body,
    timestamp,
    nonce,
  })

  return {
    'X-App-Key': input.appKey,
    'X-Timestamp': timestamp,
    'X-Nonce': nonce,
    'X-Sign': sign,
  }
}

export function buildCallbackSign(input: {
  callbackSecret: string
  rawBody: string
  timestamp: string
}): string {
  const content = `body_sha256=${sha256Hex(input.rawBody)}&timestamp=${input.timestamp}`
  return hmacSha256Hex(input.callbackSecret, content)
}

export function verifyCallbackSign(input: {
  callbackSecret: string
  rawBody: string
  timestamp: string
  sign: string
}): boolean {
  const expected = buildCallbackSign({
    callbackSecret: input.callbackSecret,
    rawBody: input.rawBody,
    timestamp: input.timestamp,
  })

  return timingSafeEqualString(
    expected,
    String(input.sign || '')
      .trim()
      .toLowerCase(),
  )
}

export function timingSafeEqualString(left: string, right: string): boolean {
  const leftBuffer = Buffer.from(left, 'utf8')
  const rightBuffer = Buffer.from(right, 'utf8')

  if (leftBuffer.length !== rightBuffer.length) {
    return false
  }

  return crypto.timingSafeEqual(leftBuffer, rightBuffer)
}
