import crypto from 'node:crypto'
import type { JsonObject } from '../../types/json.js'

import { createHttpError } from '../../utils/http.js'
import { assertOpen91Config } from './config.js'
import { normalizeOpen91String } from './payload.js'

export function buildOpen91SignSource(params: JsonObject = {}, { secret } = assertOpen91Config()) {
  const entries = Object.entries(params)
    .filter(([key]) => key !== 'sign')
    .sort(([left], [right]) => {
      if (left === right) {
        return 0
      }
      return left < right ? -1 : 1
    })

  const queryString = entries
    .map(([key, value]) => `${key}=${stringifyOpen91SignValue(value)}`)
    .join('&')

  return `${secret}${queryString}${secret}`
}

export function signOpen91Payload(params: JsonObject = {}, config = assertOpen91Config()) {
  return crypto
    .createHash('md5')
    .update(buildOpen91SignSource(params, config), 'utf8')
    .digest('hex')
    .toUpperCase()
}

export function verifyOpen91Signature(params: JsonObject = {}, config = assertOpen91Config()) {
  const expected = signOpen91Payload(params, config)
  const actual = normalizeOpen91String(params.sign).toUpperCase()
  return expected === actual
}

export function assertOpen91Signature(params: JsonObject = {}, config = assertOpen91Config()) {
  if (!verifyOpen91Signature(params, config)) {
    throw createHttpError('验签失败', {
      statusCode: 400,
      errorCode: 'open91_invalid_signature',
    })
  }
}

export function encryptOpen91Cards(cards: unknown[] = [], secret = assertOpen91Config().secret) {
  const normalizedSecret = normalizeOpen91String(secret)
  if (normalizedSecret.length !== 32) {
    throw createHttpError('91卡券 cards 加密密钥长度必须为 32 个字符', {
      statusCode: 500,
      errorCode: 'open91_invalid_cards_secret_length',
    })
  }

  const plainText = JSON.stringify(Array.isArray(cards) ? cards : [])
  const cipher = crypto.createCipheriv('aes-256-ecb', Buffer.from(normalizedSecret, 'utf8'), null)
  cipher.setAutoPadding(true)

  return `${cipher.update(plainText, 'utf8', 'base64')}${cipher.final('base64')}`
}

export function buildOpen91Cards(cards: unknown[] = [], config = assertOpen91Config()) {
  const encoding = normalizeOpen91String(config.cardsEncoding).toLowerCase()
  if (encoding && encoding !== 'aes-256-ecb-base64') {
    throw createHttpError(`暂不支持的 cardsEncoding: ${config.cardsEncoding}`, {
      statusCode: 500,
      errorCode: 'open91_unsupported_cards_encoding',
    })
  }

  return encryptOpen91Cards(cards, config.secret)
}

export function stringifyOpen91SignValue(value: unknown) {
  if (typeof value === 'number' && Number.isFinite(value)) {
    return String(value)
  }

  if (typeof value === 'boolean') {
    return value ? 'true' : 'false'
  }

  if (value == null) {
    return ''
  }

  return String(value)
}
