import { createHash, constants, publicEncrypt } from 'node:crypto'
import type { JsonObject } from '../../../types/json.js'

import { createHttpError } from '../../../utils/http.js'
import { resolveCloudtentaclesConfig } from './helpers.js'

export function md5CloudtentaclesPassword(password: unknown) {
  return createHash('md5')
    .update(String(password || ''), 'utf8')
    .digest('hex')
}

export function encryptCloudtentaclesPayload(payload: JsonObject = {}, options: JsonObject = {}) {
  const config = resolveCloudtentaclesConfig(options)
  const publicKeyPem = String(config.publicKeyPem || '').trim()

  if (!publicKeyPem) {
    throw createHttpError('cloudtentacles 公钥未配置', {
      statusCode: 500,
      errorCode: 'cloudtentacles_public_key_missing',
    })
  }

  const timestamp = Number(options.timestamp || Date.now())
  const randomValue =
    String(options.randomValue || Math.random().toString(16)).trim() || Math.random().toString(16)
  const normalizedPayload = removeEmptyFields(payload)
  const plaintext = JSON.stringify({
    t: timestamp,
    r: randomValue,
    s: String(options.clientSource || config.clientSource || 'ct-client').trim() || 'ct-client',
    ...normalizedPayload,
  })

  try {
    const encrypted = publicEncrypt(
      {
        key: publicKeyPem,
        padding: constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256',
      },
      Buffer.from(plaintext, 'utf8'),
    )

    return {
      covert: encrypted.toString('base64'),
      t: timestamp,
      r: randomValue,
      plaintext,
    }
  } catch {
    throw createHttpError('cloudtentacles 加密失败', {
      statusCode: 500,
      errorCode: 'cloudtentacles_encrypt_failed',
    })
  }
}

function removeEmptyFields(payload: unknown) {
  if (!payload || typeof payload !== 'object') {
    return {}
  }

  return Object.fromEntries(
    Object.entries(payload).filter(
      ([, value]) => value !== '' && value !== null && typeof value !== 'undefined',
    ),
  )
}
