/**
 * 快手行业电子凭证接口一键测试脚本
 *
 * 用法：
 *   npm run test:industry
 *   npm run test:industry -- --oid=自定义订单号 --num=5
 *
 * 前提：
 *   1. PostgreSQL 已启动且迁移已完成 (npm run db:migrate)
 *   2. .env 中配置了 KUASHOU_INDUSTRY_APP_KEY 和 KUASHOU_INDUSTRY_SIGN_SECRET
 *      （未配置时使用测试默认值，可与 DB 中已插入的数据联调）
 */

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

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

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')])

process.env.KUASHOU_INDUSTRY_APP_KEY =
  process.env.KUASHOU_INDUSTRY_APP_KEY || 'test_industry_app_key'
process.env.KUASHOU_INDUSTRY_SIGN_SECRET =
  process.env.KUASHOU_INDUSTRY_SIGN_SECRET || 'test_industry_sign_secret'
process.env.KUASHOU_INDUSTRY_SHOP_ID = process.env.KUASHOU_INDUSTRY_SHOP_ID || 'test_shop'

const args = parseArgs(process.argv.slice(2))

if (args.help) {
  printHelp()
  process.exit(0)
}

const [
  { handleSendCode },
  { handleQueryCode },
  { handleDestroyCode },
  { signKuaishouIndustryPayload },
  { getKuaishouIndustryConfig },
  { closeDb },
] = await Promise.all([
  import('../src/services/platforms/kuaishou-industry/send-code-service.js'),
  import('../src/services/platforms/kuaishou-industry/query-code-service.js'),
  import('../src/services/platforms/kuaishou-industry/destroy-code-service.js'),
  import('../src/services/platforms/kuaishou-industry/crypto.js'),
  import('../src/services/platforms/kuaishou-industry/config.js'),
  import('../src/db/client.js'),
])

const config = getKuaishouIndustryConfig()
const testOid = String(args.oid || `TEST_KS${Date.now()}`).trim()
const testNum = normalizePositiveInteger(args.num, 3)
const signMethod = String(args.signMethod || 'MD5')
  .trim()
  .toUpperCase()

console.log('')
console.log('╔══════════════════════════════════════════════════════╗')
console.log('║       快手行业电子凭证 接口一键测试                    ║')
console.log('╠══════════════════════════════════════════════════════╣')
console.log(`║  appKey     : ${config.appKey.padEnd(36)}║`)
console.log(`║  signSecret : ${'*'.repeat(12).padEnd(36)}║`)
console.log(`║  signMethod : ${signMethod.padEnd(36)}║`)
console.log(`║  测试订单号 : ${testOid.padEnd(36)}║`)
console.log(`║  发码数量   : ${String(testNum).padEnd(36)}║`)
console.log('╚══════════════════════════════════════════════════════╝')
console.log('')

let passed = 0
let failed = 0
let total = 0

try {
  // ─────────────────────────────────────────────────────────
  // 1. 通知商家发码
  // ─────────────────────────────────────────────────────────
  total++
  printStep(1, '通知商家发码 POST /api/v1/open/kuaishou-industry/send-code')

  const sendCodeBizParams: Record<string, unknown> = {
    oid: testOid,
    sellerId: '2174425348',
    num: testNum,
    itemId: '20842040339391',
    skuId: '87457167264391',
    itemTitle: '测试电子凭证商品',
    sendType: 'VIRTUAL',
    eticketType: 'DINING_OPEN_TICKET',
    token: `test-token-${testOid}`,
    certExpireType: 3,
    certExpDays: 30,
    certActualStartTime: Date.now(),
    certActualEndTime: Date.now() + 30 * 24 * 60 * 60 * 1000,
  }

  const sendCodeParams = buildRequestParams(config.appKey, sendCodeBizParams, signMethod)
  const sendCodeResult = await handleSendCode(sendCodeParams)

  printResult('通知商家发码', sendCodeResult)
  if (sendCodeResult.result === 1) {
    passed++
    console.log(`        返回卡券数: ${sendCodeResult.data?.etickets?.length || 0}`)
    const firstTicket = sendCodeResult.data?.etickets?.[0]
    if (firstTicket) {
      console.log(`        首张卡券 ID: ${firstTicket.id}, 状态: ${firstTicket.status}`)
    }
  } else {
    failed++
  }

  // ─────────────────────────────────────────────────────────
  // 2. 重复发码（幂等性测试）
  // ─────────────────────────────────────────────────────────
  total++
  printStep(2, '重复发码（幂等性测试）')

  const sendCodeRepeatResult = await handleSendCode(sendCodeParams)

  printResult('重复发码', sendCodeRepeatResult)
  if (sendCodeRepeatResult.result === 1) {
    passed++
    console.log(`        返回卡券数: ${sendCodeRepeatResult.data?.etickets?.length || 0}`)
  } else {
    failed++
  }

  // ─────────────────────────────────────────────────────────
  // 3. 查询商家卡券（不传 eticketId，查全部）
  // ─────────────────────────────────────────────────────────
  total++
  printStep(3, '查询商家卡券 POST /api/v1/open/kuaishou-industry/query-code')

  const queryCodeBizParams: Record<string, unknown> = {
    oid: testOid,
    sendType: 'VIRTUAL',
    eticketType: 'DINING_OPEN_TICKET',
  }

  const queryCodeParams = buildRequestParams(config.appKey, queryCodeBizParams, signMethod)
  const queryCodeResult = await handleQueryCode(queryCodeParams)

  printResult('查询全部卡券', queryCodeResult)
  if (queryCodeResult.result === 1) {
    passed++
    console.log(`        已发货数量: ${queryCodeResult.data?.sendNum || 0}`)
    console.log(`        卡券列表数: ${queryCodeResult.data?.etickets?.length || 0}`)
    queryCodeResult.data?.etickets?.forEach((eticket: Record<string, unknown>, index: number) => {
      console.log(
        `          [${index + 1}] id=${eticket.id} status=${eticket.status} num=${eticket.num}`,
      )
    })
  } else {
    failed++
  }

  // ─────────────────────────────────────────────────────────
  // 4. 查询单个卡券（传 eticketId）
  // ─────────────────────────────────────────────────────────
  if (queryCodeResult.data?.etickets?.length > 0) {
    total++
    const targetEticketId = queryCodeResult.data.etickets[0].id as string
    printStep(4, `查询单个卡券（eticketId=${targetEticketId}）`)

    const querySingleBizParams: Record<string, unknown> = {
      oid: testOid,
      eticketId: targetEticketId,
      sendType: 'VIRTUAL',
      eticketType: 'DINING_OPEN_TICKET',
    }

    const querySingleParams = buildRequestParams(config.appKey, querySingleBizParams, signMethod)
    const querySingleResult = await handleQueryCode(querySingleParams)

    printResult('查询单个卡券', querySingleResult)
    if (querySingleResult.result === 1) {
      passed++
      console.log(`        卡券 ID: ${querySingleResult.data?.etickets?.[0]?.id}`)
      console.log(`        状态   : ${querySingleResult.data?.etickets?.[0]?.status}`)
    } else {
      failed++
    }
  } else {
    console.log('  ⚠ 跳过（无卡券可查询）')
  }

  // ─────────────────────────────────────────────────────────
  // 5. 查询不存在的订单
  // ─────────────────────────────────────────────────────────
  total++
  const fakeOid = `FAKE_NOT_EXIST_${Date.now()}`
  printStep(5, '查询不存在的订单（错误码验证）')

  const queryMissingBizParams: Record<string, unknown> = {
    oid: fakeOid,
    sendType: 'VIRTUAL',
  }

  const queryMissingParams = buildRequestParams(config.appKey, queryMissingBizParams, signMethod)
  const queryMissingResult = await handleQueryCode(queryMissingParams)

  if (queryMissingResult.result === 4012002) {
    passed++
    console.log(`  └─ ✅ 查询不存在订单: result=4012002 (订单不存在，符合预期)`)
    console.log(`        错误信息: ${queryMissingResult.error_msg}`)
  } else {
    failed++
    console.log(
      `  └─ ❌ 查询不存在订单: 期望 result=4012002，实际 result=${queryMissingResult.result}`,
    )
  }

  // ─────────────────────────────────────────────────────────
  // 6. 通知商家销毁（指定卡券 ID）
  // ─────────────────────────────────────────────────────────
  if (queryCodeResult.data?.etickets?.length > 0) {
    total++
    const destroyTargetIds = queryCodeResult.data.etickets
      .slice(0, 1)
      .map((e: Record<string, unknown>) => ({
        id: String(e.id),
        num: 1,
        goodsValue: 100,
      }))
    printStep(6, `通知商家销毁（指定卡券 id=${destroyTargetIds[0].id}）`)

    const destroyBizParams: Record<string, unknown> = {
      oid: testOid,
      reason: 'USER_APPLY_REFUND',
      etickets: destroyTargetIds,
    }

    const destroyParams = buildRequestParams(config.appKey, destroyBizParams, signMethod)
    const destroyResult = await handleDestroyCode(destroyParams)

    printResult('通知商家销毁', destroyResult)
    if (destroyResult.result === 1) {
      passed++
    } else {
      failed++
    }

    // 销毁后再次查询，验证卡券状态变为 DESTROYED
    total++
    printStep(7, '销毁后验证卡券状态')

    const verifyDestroyBizParams: Record<string, unknown> = {
      oid: testOid,
      eticketId: destroyTargetIds[0].id,
      sendType: 'VIRTUAL',
      eticketType: 'DINING_OPEN_TICKET',
    }

    const verifyDestroyParams = buildRequestParams(
      config.appKey,
      verifyDestroyBizParams,
      signMethod,
    )
    const verifyDestroyResult = await handleQueryCode(verifyDestroyParams)

    printResult('销毁后查询', verifyDestroyResult)
    const verifyStatus = verifyDestroyResult.data?.etickets?.[0]?.status
    if (verifyDestroyResult.result === 1 && verifyStatus === 'DESTROYED') {
      passed++
      console.log(`        卡券状态: ${verifyStatus}`)
    } else {
      failed++
      console.log(
        `        期望 status=DESTROYED，实际 status=${verifyStatus}, result=${verifyDestroyResult.result}`,
      )
    }
  } else {
    console.log('  ⚠ 跳过（无卡券可销毁）')
  }

  // ─────────────────────────────────────────────────────────
  // 8. 整单销毁（不传 etickets，销毁剩余全部）
  // ─────────────────────────────────────────────────────────
  total++
  printStep(8, '整单销毁（不传 etickets，关闭全部剩余卡券）')

  const destroyAllBizParams: Record<string, unknown> = {
    oid: testOid,
    reason: 'ETICKET_EXPIRED',
  }

  const destroyAllParams = buildRequestParams(config.appKey, destroyAllBizParams, signMethod)
  const destroyAllResult = await handleDestroyCode(destroyAllParams)

  printResult('整单销毁', destroyAllResult)
  if (destroyAllResult.result === 1) {
    passed++
  } else {
    failed++
  }
} finally {
  await closeDb()
}

// ─────────────────────────────────────────────────────────
console.log('')
console.log('╔══════════════════════════════════════════════════════╗')
console.log(
  `║  测试完成: ${String(passed).padStart(2)}/${total} 通过, ${String(failed).padStart(2)}/${total} 失败                  ║`,
)
console.log('╚══════════════════════════════════════════════════════╝')
console.log('')

if (failed > 0) {
  process.exitCode = 1
}

// ─────────────────── helpers ───────────────────

function buildRequestParams(
  appKey: string,
  bizParams: Record<string, unknown>,
  method: string,
): Record<string, unknown> {
  const paramStr = JSON.stringify(bizParams)

  const params: Record<string, unknown> = {
    appkey: appKey,
    version: '1',
    timestamp: Date.now(),
    signMethod: method,
    access_token: `test-access-token-${testOid}`,
    method: 'integration.virtual.eticket.callback',
    param: paramStr,
  }

  const sign = signKuaishouIndustryPayload(params, method as 'MD5' | 'HMAC_SHA256')
  params.sign = sign

  return params
}

function normalizePositiveInteger(value: unknown, fallback: number): number {
  const parsed = Number(value)
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
}

function printStep(stepNum: number, title: string) {
  console.log('')
  console.log(`  ┌─ [${stepNum}] ${title}`)
}

function printResult(label: string, result: Record<string, unknown>) {
  const ok = result.result === 1
  const icon = ok ? '✅' : '❌'
  const resultText = ok
    ? `result=${result.result}`
    : `result=${result.result} error_msg="${result.error_msg}"`
  console.log(`  └─ ${icon} ${label}: ${resultText}`)
}

function parseArgs(rawArgs: string[]) {
  const parsed: Record<string, unknown> = {}

  for (const rawArg of rawArgs) {
    const arg = String(rawArg || '').trim()
    if (!arg) continue
    if (arg === '--help' || arg === '-h') {
      parsed.help = true
      continue
    }

    const normalized = arg.startsWith('--') ? arg.slice(2) : arg
    const eqIdx = normalized.indexOf('=')
    if (eqIdx < 0) {
      parsed[normalized] = true
      continue
    }

    const key = normalized.slice(0, eqIdx).trim()
    const value = normalized.slice(eqIdx + 1).trim()
    if (key) {
      parsed[key] = value
    }
  }

  return parsed
}

function printHelp() {
  console.log(`
快手行业电子凭证接口一键测试

用法:
  npm run test:industry
  npm run test:industry -- --oid=自定义订单号 --num=5 --signMethod=HMAC_SHA256

参数:
  --oid         测试订单号，默认自动生成 (TEST_KS + 时间戳)
  --num         发码数量，默认 3
  --signMethod  签名算法 MD5 或 HMAC_SHA256，默认 MD5

测试内容:
  1. 通知商家发码          — send-code
  2. 重复发码（幂等性）     — send-code (same oid)
  3. 查询全部卡券           — query-code
  4. 查询单个卡券           — query-code (指定 eticketId)
  5. 查询不存在订单         — query-code (错误码 4012002)
  6. 通知商家销毁（指定卡券）— destroy-code (指定 etickets)
  7. 销毁后验证卡券状态     — query-code (验证 DESTROYED)
  8. 整单销毁（关闭订单）   — destroy-code (不传 etickets)
`)
}
