/**
 * 生成快手 Open API 回调 curl 命令（手动测试用）
 *
 * 用法:
 *   npm run test:industry:curl                          # 发码回调 (默认)
 *   npm run test:industry:curl -- --mode=consume        # 核销回调
 *   npm run test:industry:curl -- --oid=xxx --token=xxx --accessToken=xxx
 */

import crypto from 'node:crypto'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'

import { loadEnvFiles } from '../src/config/runtime-env.js'

type JsonObject = Record<string, unknown>

const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url))
const PROJECT_ROOT = path.resolve(CURRENT_DIR, '..')
const WORKSPACE_ROOT = path.resolve(PROJECT_ROOT, '../..')

loadEnvFiles([path.join(WORKSPACE_ROOT, '.env'), path.join(PROJECT_ROOT, '.env')])

const accessToken = String(process.env.KUASHOU_INDUSTRY_ACCESS_TOKEN || 'your_access_token').trim()
const appKey = String(process.env.KUASHOU_INDUSTRY_APP_KEY || 'your_app_key').trim()
const signSecret = String(process.env.KUASHOU_INDUSTRY_SIGN_SECRET || 'your_sign_secret').trim()

const args = parseArgs(process.argv.slice(2))
const mode = String(args.mode || 'send').trim() // send | consume | destroy
const oid = String(args.oid || String(Date.now())).trim() // 快手要求纯数字 oid
const sendNum = normalizeInt(args.num, 3)
const token = String(args.token || `test-token-${Date.now()}`).trim()
const bodyAccessToken = String(args.accessToken || accessToken).trim()

const KUAISHOU_OPEN_API = 'https://openapi.kwaixiaodian.com'

const now = Date.now()
const validEnd = now + 30 * 24 * 60 * 60 * 1000

const bizParams: JsonObject =
  mode === 'consume'
    ? {
        oid,
        etickets: Array.from({ length: sendNum }, (_, i) => ({
          id: String(i + 1),
          num: 1,
          goodsValue: 10,
        })),
        status: 'CONSUMED',
        consumeType: 'consume',
        consumeTime: now,
        storeName: '测试门店',
        storeAddress: '测试地址',
        seriallNum: `SN${Date.now()}`,
        token,
      }
    : mode === 'destroy'
      ? {
          oid,
          etickets: Array.from({ length: sendNum }, (_, i) => ({
            id: String(i + 1),
            num: 1,
            goodsValue: 100,
          })),
          reason: 'ETICKET_EXPIRED',
          token,
        }
      : {
          oid,
          sendType: 'VIRTUAL',
          etickets: Array.from({ length: sendNum }, (_, i) => ({
            id: String(i + 1),
            num: 1,
            validStartTime: now,
            validEndTime: validEnd,
          })),
          sendNum,
          token,
        }

const method =
  mode === 'consume'
    ? 'integration.callback.virtual.eticket.consume'
    : mode === 'destroy'
      ? 'integration.callback.virtual.eticket.destroy'
      : 'integration.callback.virtual.eticket.send'

const endpoint =
  mode === 'consume'
    ? '/integration/callback/virtual/eticket/consume'
    : mode === 'destroy'
      ? '/integration/callback/virtual/eticket/destroy'
      : '/integration/callback/virtual/eticket/send'

const paramStr = JSON.stringify(bizParams)

const signParams: JsonObject = {
  method,
  appkey: appKey,
  access_token: bodyAccessToken,
  version: '1',
  timestamp: now,
  signMethod: 'MD5',
  param: paramStr,
}

const sign = signPayload(signParams, signSecret)

console.log('')
const modeLabel = mode === 'consume' ? '核销' : mode === 'destroy' ? '销毁' : '发码'
console.log(`# 电子凭证${modeLabel}回调 curl 命令`)
console.log(`# oid=${oid}  sendNum=${sendNum}  access_token=${bodyAccessToken.slice(0, 10)}...`)
console.log(`# 先测试网络连通性:`)
console.log(
  `curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 https://openapi.kwaixiaodian.com/`,
)
console.log('# 如果返回 000，说明网络不通，需要关闭代理或换服务器')
console.log('')
console.log('curl -X POST \\')
console.log(`  '${KUAISHOU_OPEN_API}${endpoint}' \\`)
console.log("  -H 'Content-Type: application/x-www-form-urlencoded' \\")
console.log(`  --data-urlencode 'method=${method}' \\`)
console.log(`  --data-urlencode 'appkey=${appKey}' \\`)
console.log(`  --data-urlencode 'access_token=${bodyAccessToken}' \\`)
console.log(`  --data-urlencode 'version=1' \\`)
console.log(`  --data-urlencode 'timestamp=${now}' \\`)
console.log(`  --data-urlencode 'signMethod=MD5' \\`)
console.log(`  --data-urlencode 'sign=${sign}' \\`)
console.log(`  --data-urlencode 'param=${paramStr}'`)
console.log('')

// 本地签名校验（不调快手）
console.log('# 本地签名校验（不会真正调用快手）:')
const localEndpoint =
  mode === 'consume' ? 'consume-code' : mode === 'destroy' ? 'destroy-code' : 'send-code'
console.log(
  `curl -s -X POST http://127.0.0.1:3000/api/v1/open/kuaishou-industry/${localEndpoint} \\`,
)
console.log("  -H 'Content-Type: application/x-www-form-urlencoded' \\")
console.log(
  `  -d 'appkey=${appKey}&version=1&timestamp=${now}&signMethod=MD5&access_token=&method=&sign=${sign}&param=${encodeURIComponent(paramStr)}'`,
)
console.log('')

function signPayload(params: JsonObject, secret: string): string {
  const entries = Object.entries(params)
    .filter(([k]) => k !== 'sign' && k !== 'signSecret')
    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
  const qs = entries.map(([k, v]) => `${k}=${stringify(v)}`).join('&')
  return crypto
    .createHash('md5')
    .update(`${qs}&signSecret=${secret}`, 'utf8')
    .digest('hex')
    .toLowerCase()
}

function stringify(v: unknown): string {
  if (typeof v === 'number' && Number.isFinite(v)) return String(v)
  if (typeof v === 'boolean') return v ? 'true' : 'false'
  if (v == null) return ''
  if (typeof v === 'object') return JSON.stringify(v, Object.keys(v as JsonObject).sort())
  return String(v)
}

function normalizeInt(v: unknown, d: number): number {
  const n = Number(v)
  return Number.isInteger(n) && n > 0 ? n : d
}

function parseArgs(raw: string[]): JsonObject {
  const p: JsonObject = {}
  for (const a of raw) {
    const arg = String(a || '').trim()
    if (!arg) continue
    const n = arg.startsWith('--') ? arg.slice(2) : arg
    const eq = n.indexOf('=')
    if (eq < 0) {
      p[n] = true
      continue
    }
    p[n.slice(0, eq).trim()] = n.slice(eq + 1).trim()
  }
  return p
}
