import crypto from 'node:crypto'

import { runtimeConfig } from '../../config/runtime.js'
import { createWebhookEvent, updateWebhookEvent } from '../../repositories/webhook-event-repo.js'
import { enrichAgisoXianyuTradeOrder } from '../platforms/agiso/xianyu/order-detail-service.js'
import {
  extractAgisoTradeOrderItemSources,
  extractAgisoTradePayload,
  resolveAgisoTradePlatformOrderId,
} from './agiso-trade-parsing.js'
import { upsertOrderFromWebhook } from './order-service.js'
import { hasConfiguredOrderItems } from './product-match-service.js'
import { createHttpError } from '../../utils/http.js'
import { parseJsonObject } from '../../utils/json.js'
import { logWebhook } from '../../utils/logger.js'
import { parseAmountToFen } from '../../utils/money.js'
import { nowIso } from '../../utils/time.js'

type AgisoTradeWebhookDeps = {
  updateWebhookEvent?: typeof updateWebhookEvent
  hasConfiguredOrderItems?: typeof hasConfiguredOrderItems
  upsertOrderFromWebhook?: typeof upsertOrderFromWebhook
  enrichAgisoXianyuTradeOrder?: typeof enrichAgisoXianyuTradeOrder
}

export async function processAgisoTradeWebhook(requestLike) {
  const parsed = parseAgisoTradeRequest(requestLike)
  const webhookEvent = await createWebhookEvent(buildWebhookEventInput(requestLike, parsed))

  logWebhook('[webhook-service/agiso]', 'Webhook 已解析并写入 webhook_events', {
    requestId: requestLike.requestId || '',
    webhookEventId: webhookEvent.id,
    provider: parsed.provider,
    platform: parsed.platform,
    shopId: parsed.shopId,
    shopName: parsed.shopName,
    eventKey: parsed.eventKey,
    eventType: parsed.eventType,
    platformOrderId: parsed.platformOrderId,
    signatureValid: parsed.signatureValid,
  })

  return executeAgisoTradeWebhook(parsed, webhookEvent.id, { requestId: requestLike.requestId || '' })
}

export async function replayAgisoTradeWebhookEvent(webhookEvent) {
  const requestLike = {
    requestId: `replay-${webhookEvent.id}`,
    headers: safeParseJson(webhookEvent.headers_json),
    query: safeParseJson(webhookEvent.query_json),
    body: safeParseJson(webhookEvent.body_json),
  }
  const parsed = parseAgisoTradeRequest(requestLike)

  logWebhook('[webhook-service/agiso]', '开始重放 webhook 事件', {
    requestId: requestLike.requestId,
    webhookEventId: webhookEvent.id,
    provider: parsed.provider,
    platform: parsed.platform,
    shopId: parsed.shopId,
    shopName: parsed.shopName,
    eventKey: parsed.eventKey,
    eventType: parsed.eventType,
    platformOrderId: parsed.platformOrderId,
  })

  return executeAgisoTradeWebhook(parsed, webhookEvent.id, { requestId: requestLike.requestId })
}

export function buildWebhookEventInput(requestLike, parsed) {
  return {
    provider: parsed.provider,
    platform: parsed.platform,
    shopId: parsed.shopId,
    shopName: parsed.shopName,
    eventType: parsed.eventType,
    eventKey: parsed.eventKey,
    signatureValid: parsed.signatureValid,
    headersJson: JSON.stringify(requestLike.headers || {}),
    queryJson: JSON.stringify(requestLike.query || {}),
    bodyJson: JSON.stringify(requestLike.body || {}),
    processed: false,
    processError: '',
    relatedOrderId: null,
    createdAt: nowIso(),
  }
}

async function executeAgisoTradeWebhook(parsed, webhookEventId, { requestId = '' } = {}) {
  return executeAgisoTradeWebhookWithDeps(parsed, webhookEventId, { requestId })
}

export async function executeAgisoTradeWebhookWithDeps(
  parsed,
  webhookEventId,
  { requestId = '' } = {},
  deps: AgisoTradeWebhookDeps = {},
) {
  const updateEvent = deps.updateWebhookEvent || updateWebhookEvent
  const hasConfiguredItems = deps.hasConfiguredOrderItems || hasConfiguredOrderItems
  const upsertOrder = deps.upsertOrderFromWebhook || upsertOrderFromWebhook

  try {
    if (!parsed.signatureValid) {
      throw createHttpError('验签失败', {
        statusCode: 400,
        errorCode: 'invalid_signature',
      })
    }

    if (!parsed.platformOrderId) {
      throw createHttpError('缺少平台订单号', {
        statusCode: 400,
        errorCode: 'missing_platform_order_id',
      })
    }

    const ignoreReason = resolveAgisoTradeIgnoreReason(parsed)
    if (ignoreReason) {
      await updateEvent(webhookEventId, {
        processed: true,
        process_error: `ignored_${ignoreReason}`,
        related_order_id: null,
      })

      logWebhook('[webhook-service/agiso]', 'Webhook 已忽略：当前通知不应再次触发履约发送', {
        requestId,
        webhookEventId,
        provider: parsed.provider,
        platform: parsed.platform,
        shopId: parsed.shopId,
        shopName: parsed.shopName,
        eventKey: parsed.eventKey,
        eventType: parsed.eventType,
        platformOrderId: parsed.platformOrderId,
        ignoreReason,
      })

      return {
        accepted: true,
        ignored: true,
        ignoreReason,
        provider: parsed.provider,
        platform: parsed.platform,
        shopId: parsed.shopId,
        shopName: parsed.shopName,
        platformRaw: parsed.platformRaw,
        eventType: parsed.eventType,
        platformOrderId: parsed.platformOrderId,
        orderId: null,
        totalAmountFen: Number(parsed.totalAmount || 0),
        enriched: false,
        enrichReason: 'skipped_ignored_event',
        taskCount: 0,
        messageDeliveries: [],
        tasks: [],
      }
    }

    const shouldProcess = await hasConfiguredItems({
      provider: parsed.provider,
      platform: parsed.platform,
      shopId: parsed.shopId,
      shopIdAliases: parsed.shopIdAliases,
      items: parsed.items,
    })

    if (!shouldProcess) {
      await updateEvent(webhookEventId, {
        processed: true,
        process_error: 'ignored_unconfigured_product',
        related_order_id: null,
      })

      logWebhook('[webhook-service/agiso]', 'Webhook 已忽略：未命中任何已配置履约商品', {
        requestId,
        webhookEventId,
        provider: parsed.provider,
        platform: parsed.platform,
        shopId: parsed.shopId,
        shopName: parsed.shopName,
        platformOrderId: parsed.platformOrderId,
        rawItemCount: Array.isArray(parsed.items) ? parsed.items.length : 0,
      })

      return {
        accepted: true,
        ignored: true,
        ignoreReason: 'unconfigured_product',
        provider: parsed.provider,
        platform: parsed.platform,
        shopId: parsed.shopId,
        shopName: parsed.shopName,
        platformRaw: parsed.platformRaw,
        eventType: parsed.eventType,
        platformOrderId: parsed.platformOrderId,
        orderId: null,
        totalAmountFen: Number(parsed.totalAmount || 0),
        enriched: false,
        enrichReason: 'skipped_unconfigured_product',
        taskCount: 0,
        messageDeliveries: [],
        tasks: [],
      }
    }

    const enriched = await enrichTradeBeforeUpsert(parsed, {
      requestId,
      webhookEventId,
    }, deps)
    const result = await upsertOrder(enriched.parsed)
    await updateEvent(webhookEventId, {
      processed: true,
      process_error: result.ignored ? 'ignored_unconfigured_product' : '',
      related_order_id: result.order?.id || null,
    })

    logWebhook('[webhook-service/agiso]', 'Webhook 业务处理成功', {
      requestId,
      webhookEventId,
      provider: parsed.provider,
      platform: parsed.platform,
      shopId: parsed.shopId,
      shopName: parsed.shopName,
      eventKey: parsed.eventKey,
      eventType: parsed.eventType,
      platformOrderId: enriched.parsed.platformOrderId,
      orderId: result.order?.id || null,
      ignored: Boolean(result.ignored),
      ignoreReason: String(result.ignoreReason || ''),
      enriched: enriched.enriched,
      enrichReason: enriched.reason || '',
      totalAmountFen: Number(enriched.parsed.totalAmount || 0),
      taskCount: result.tasks.length,
      messageDeliveryCount: Array.isArray(result.messageDeliveries) ? result.messageDeliveries.length : 0,
    })

    return {
      accepted: true,
      provider: enriched.parsed.provider,
      platform: enriched.parsed.platform,
      shopId: enriched.parsed.shopId,
      shopName: enriched.parsed.shopName,
      platformRaw: enriched.parsed.platformRaw,
      eventType: enriched.parsed.eventType,
      platformOrderId: enriched.parsed.platformOrderId,
      orderId: result.order?.id || null,
      totalAmountFen: Number(enriched.parsed.totalAmount || 0),
      ignored: Boolean(result.ignored),
      ignoreReason: String(result.ignoreReason || ''),
      enriched: enriched.enriched,
      enrichReason: enriched.reason || '',
      taskCount: result.tasks.length,
      messageDeliveries: result.messageDeliveries || [],
      tasks: result.tasks.map((task) => ({
        taskId: task.id,
        taskNo: task.task_no,
        status: task.task_status,
      })),
    }
  } catch (error) {
    await updateEvent(webhookEventId, {
      processed: false,
      process_error: error instanceof Error ? error.message : String(error || ''),
      related_order_id: null,
    })

    logWebhook(
      '[webhook-service/agiso]',
      'Webhook 业务处理失败',
      {
        requestId,
        webhookEventId,
        provider: parsed.provider,
        platform: parsed.platform,
        shopId: parsed.shopId,
        shopName: parsed.shopName,
        eventKey: parsed.eventKey,
        eventType: parsed.eventType,
        platformOrderId: parsed.platformOrderId,
        signatureValid: parsed.signatureValid,
        error,
      },
      { level: 'error' },
    )
    throw error
  }
}

async function enrichTradeBeforeUpsert(
  parsed,
  { requestId = '', webhookEventId = null } = {},
  deps: AgisoTradeWebhookDeps = {},
) {
  const enrichOrder = deps.enrichAgisoXianyuTradeOrder || enrichAgisoXianyuTradeOrder

  if (parsed.provider !== 'agiso' || parsed.platform !== 'xianyu') {
    return { parsed, enriched: false, reason: 'not_supported' }
  }

  if (!shouldEnrichAgisoXianyuTrade(parsed)) {
    return { parsed, enriched: false, reason: 'enough_fields_present' }
  }

  const detailResult = await enrichOrder(parsed, { requestId })
  const nextParsed = detailResult?.parsed || parsed

  logWebhook('[webhook-service/agiso]', 'Agiso webhook 订单补查结束', {
    requestId,
    webhookEventId,
    provider: nextParsed.provider,
    platform: nextParsed.platform,
    shopId: nextParsed.shopId,
    platformOrderId: nextParsed.platformOrderId,
    enriched: Boolean(detailResult?.enriched),
    reason: String(detailResult?.reason || ''),
    totalAmountFen: Number(nextParsed.totalAmount || 0),
    paidAt: nextParsed.paidAt || null,
    errorMessage: String(detailResult?.errorMessage || ''),
  })

  return {
    parsed: nextParsed,
    enriched: Boolean(detailResult?.enriched),
    reason: String(detailResult?.reason || ''),
    errorMessage: String(detailResult?.errorMessage || ''),
  }
}

export function shouldEnrichAgisoXianyuTrade(parsed) {
  if (!parsed || parsed.provider !== 'agiso' || parsed.platform !== 'xianyu') {
    return false
  }

  if (Number(parsed.totalAmount || 0) <= 0) {
    return true
  }

  if (!String(parsed.buyerName || '').trim()) {
    return true
  }

  if (!String(parsed.shopName || '').trim()) {
    return true
  }

  if (!hasDetailedOrderItems(parsed.items)) {
    return true
  }

  return false
}

function hasDetailedOrderItems(items) {
  const normalizedItems = Array.isArray(items) ? items : []

  if (normalizedItems.length === 0) {
    return false
  }

  return normalizedItems.some((item) => {
    const spec = isPlainObject(item?.spec) ? item.spec : {}
    const title = pickFirstNonEmpty([
      spec.title,
      spec.Title,
      spec.itemTitle,
      spec.item_title,
      spec.goods_name,
      spec.goodsName,
      item?.skuName,
    ])
    const skuCode = String(item?.skuCode || '').trim()

    return Boolean(title && title !== skuCode)
  })
}

export function parseAgisoTradeRequest(requestLike) {
  const query = normalizeRecord(requestLike.query)
  const body = normalizeRecord(requestLike.body)
  const rawJson = String(body.json || '').trim()
  const payload = rawJson ? parsePayloadJson(rawJson) : extractAgisoTradePayload(body)
  const timestamp = String(query.timestamp || '').trim()
  const sign = String(query.sign || '').trim().toLowerCase()
  const provider = 'agiso'
  const platformRaw = pickFirstNonEmpty([
    query.fromPlatform,
    query.from_platform,
    body.fromPlatform,
    body.from_platform,
    payload.fromPlatform,
    payload.FromPlatform,
    payload.platform,
    payload.Platform,
  ])
  const platform = resolveBusinessPlatform(platformRaw)
  const shop = resolveShop(payload)
  const eventType = resolveEventType(query.aopic, payload)
  const signatureValid = verifyAgisoSignature({ rawJson, timestamp, sign })
  const platformOrderId = resolveAgisoTradePlatformOrderId(payload)

  return {
    provider,
    platform,
    platformRaw,
    eventType,
    eventKey: [provider, platform || 'unknown', shop.shopId || 'unknown', platformOrderId || 'unknown', eventType, timestamp || 'na'].join(':'),
    signatureValid,
    platformOrderId,
    shopId: shop.shopId,
    shopName: shop.shopName,
    orderStatus: resolveOrderStatus(eventType, payload),
    payStatus: resolvePayStatus(eventType, payload),
    buyerId: pickFirstNonEmpty([
      payload.buyer_id,
      payload.buyerId,
      payload.BuyerId,
      payload.openid,
      payload.BuyerOpenUid,
      payload.buyer_open_uid,
      payload.buyerOpenUid,
    ]),
    buyerName: pickFirstNonEmpty([
      payload.buyer_name,
      payload.buyerName,
      payload.BuyerName,
      payload.nick,
      payload.BuyerNick,
      payload.buyer_nick,
      payload.buyerNick,
    ]),
    receiverContact: pickFirstNonEmpty([
      payload.receiver_contact,
      payload.receiverContact,
      payload.mobile,
      payload.phone,
      payload.receiver_mobile,
      payload.receiverMobile,
    ]),
    totalAmount: parseAmountToFen(
      pickFirstNonEmpty([
        payload.total_fee,
        payload.totalFee,
        payload.TotalFee,
        payload.pay_fee,
        payload.payFee,
        payload.Payment,
        payload.payment,
      ]),
    ),
    currency: pickFirstNonEmpty([payload.currency, 'CNY']) || 'CNY',
    paidAt: resolvePaidAt(eventType, payload),
    rawPayload: payload,
    items: normalizeOrderItems(payload),
  }
}

export function verifyAgisoSignatureWithSecret({ rawJson, timestamp, sign, appSecret }) {
  const normalizedSecret = String(appSecret || '').trim()

  if (!normalizedSecret) {
    return true
  }

  if (!rawJson || !timestamp || !sign) {
    return false
  }

  const documentedDigest = crypto
    .createHash('md5')
    .update(`${normalizedSecret}json${rawJson}timestamp${timestamp}${normalizedSecret}`, 'utf8')
    .digest('hex')
    .toLowerCase()

  if (documentedDigest === sign) {
    return true
  }

  const legacyDigest = crypto
    .createHash('md5')
    .update(`${normalizedSecret}${rawJson}${timestamp}`, 'utf8')
    .digest('hex')
    .toLowerCase()

  return legacyDigest === sign
}

function verifyAgisoSignature({ rawJson, timestamp, sign }) {
  const appSecret = String(runtimeConfig.platforms.agiso.appSecret || '').trim()
  return verifyAgisoSignatureWithSecret({ rawJson, timestamp, sign, appSecret })
}

function resolveEventType(aopic, payload) {
  const normalized = String(aopic || '').trim()

  if (isTradeFinishedPayload(payload)) {
    return 'buyer_confirm_goods'
  }

  if (normalized === '1') {
    return 'payment_success'
  }

  if (normalized === '21') {
    return 'trade_create'
  }

  if (normalized === '32') {
    return 'trade_create'
  }

  if (normalized === '16' || normalized === '256') {
    return 'buyer_confirm_goods'
  }

  if (normalized === '128') {
    return 'trade_closed'
  }

  const status = resolveProviderStatus(payload)
  if (status === 'closed') {
    return 'trade_closed'
  }

  return 'trade_event'
}

export function resolveAgisoTradeIgnoreReason(parsed) {
  if (!parsed || parsed.provider !== 'agiso') {
    return ''
  }

  if (parsed.eventType === 'buyer_confirm_goods') {
    return 'buyer_confirm_goods'
  }

  if (parsed.platform === 'xianyu' && isTradeFinishedPayload(parsed.rawPayload)) {
    return 'buyer_confirm_goods'
  }

  return ''
}

function resolveOrderStatus(eventType, payload) {
  const providerStatus = resolveProviderStatus(payload)

  if (providerStatus === 'paid') {
    return 'paid'
  }

  if (providerStatus === 'closed') {
    return 'closed'
  }

  if (providerStatus === 'refunded') {
    return 'refunded'
  }

  if (eventType === 'payment_success') {
    return 'paid'
  }

  if (eventType === 'trade_closed') {
    return 'closed'
  }

  const rawStatus = normalizeInteger(
    pickFirstNonEmpty([payload.order_status, payload.orderStatus, payload.status]),
  )

  if (rawStatus === 3 || rawStatus === 4) {
    return 'paid'
  }

  if (rawStatus === 6) {
    return 'closed'
  }

  if (rawStatus === 5) {
    return 'refunded'
  }

  return 'created'
}

function resolvePayStatus(eventType, payload) {
  const providerStatus = resolveProviderStatus(payload)

  if (providerStatus === 'paid') {
    return 'paid'
  }

  if (providerStatus === 'closed') {
    return 'unpaid'
  }

  if (providerStatus === 'refunded') {
    return 'refunded'
  }

  if (eventType === 'payment_success') {
    return 'paid'
  }

  if (eventType === 'trade_closed') {
    return 'unpaid'
  }

  const rawStatus = normalizeInteger(
    pickFirstNonEmpty([payload.order_status, payload.orderStatus, payload.status]),
  )

  if (rawStatus === 3 || rawStatus === 4) {
    return 'paid'
  }

  if (rawStatus === 5) {
    return 'refunded'
  }

  return 'unpaid'
}

function resolvePaidAt(eventType, payload) {
  const providerPaidAt = normalizeProviderDateTime(
    pickFirstNonEmpty([
      payload.paid_at,
      payload.paidAt,
      payload.pay_time,
      payload.payTime,
      payload.PayTime,
    ]),
  )

  if (providerPaidAt) {
    return providerPaidAt
  }

  if (resolveProviderStatus(payload) === 'paid') {
    return nowIso()
  }

  if (eventType === 'payment_success') {
    return nowIso()
  }

  const rawStatus = normalizeInteger(
    pickFirstNonEmpty([payload.order_status, payload.orderStatus, payload.status]),
  )

  if (rawStatus === 3 || rawStatus === 4) {
    return nowIso()
  }

  return null
}

function parsePayloadJson(rawJson) {
  if (!rawJson) {
    return {}
  }

  return parseJsonObject(rawJson, {
    preserveLargeIntegers: true,
    throwOnError: true,
  })
}

function normalizeOrderItems(payload) {
  const items = extractAgisoTradeOrderItemSources(payload)

  return items.map((item) => {
    const source = isPlainObject(item) ? item : {}
    const skuDescriptor = parseExternalSkuDescriptor(
      pickFirstNonEmpty([
        source.sku,
        source.Sku,
        payload.sku,
        payload.Sku,
        payload._agisoTradeDetail?.sku,
      ]),
    )
    const rawSkuCandidates = [
      skuDescriptor.externalSkuCode,
      source.OuterSkuId,
      source.outerSkuId,
      source.outer_sku_id,
      source.OuterIid,
      source.outerIid,
      source.outer_iid,
      source.sku_code,
      source.skuCode,
      source.goods_sku,
      source.item_id,
      source.itemId,
      source.goods_id,
      source.goodsId,
      source.NumIid,
      source.num_iid,
      payload.item_id,
      payload.itemId,
    ]
    const skuCode = resolveSkuCode(rawSkuCandidates)
    const externalItemId = pickFirstNonEmpty([
      source.item_id,
      source.itemId,
      source.goods_id,
      source.goodsId,
      payload.item_id,
      payload.itemId,
    ])
    const externalSkuName = pickFirstNonEmpty([
      skuDescriptor.externalSkuName,
      source.Title,
      source.title,
      source.sku_name,
      source.skuName,
      source.goods_name,
      source.goodsName,
      skuCode,
    ])

    return {
      skuCode,
      skuName: externalSkuName,
      externalItemId,
      externalSkuCode: pickFirstNonEmpty([skuDescriptor.externalSkuCode, skuCode, externalItemId]),
      externalSkuName,
      quantity: Math.max(
        1,
        normalizeInteger(
          pickFirstNonEmpty([
            source.quantity,
            source.num,
            source.Num,
            source.buy_amount,
            payload.quantity,
            payload.num,
            payload.Num,
          ]),
        ) || 1,
      ),
      spec: source,
      snapshot: {
        externalItemId,
        externalSkuCode: pickFirstNonEmpty([skuDescriptor.externalSkuCode, skuCode, externalItemId]),
        externalSkuName,
      },
    }
  })
}

function resolveBusinessPlatform(rawPlatform) {
  const normalized = normalizePlatformKey(rawPlatform)

  if (!normalized) {
    return 'unknown'
  }

  const aliases = {
    xianyu: 'xianyu',
    idlefish: 'xianyu',
    idle: 'xianyu',
    aldsidle: 'xianyu',
    taobaoidle: 'xianyu',
    taobaoxianyu: 'xianyu',
    taobao: 'taobao',
    tb: 'taobao',
    pdd: 'pdd',
    pinduoduo: 'pdd',
    douyin: 'douyin',
    weidian: 'weidian',
    jd: 'jd',
    jingdong: 'jd',
  }

  return aliases[normalized] || normalized
}

function normalizePlatformKey(value) {
  return String(value || '')
    .trim()
    .toLowerCase()
    .replace(/[\s_-]+/g, '')
}

function resolveShop(payload) {
  const shopName = pickFirstNonEmpty([
    payload.shop_name,
    payload.shopName,
    payload.ShopName,
    payload.seller_name,
    payload.sellerName,
    payload.seller_nick,
    payload.sellerNick,
    payload.SellerNick,
  ])

  return {
    shopId: pickFirstNonEmpty([
      payload.shop_id,
      payload.shopId,
      payload.ShopId,
      payload.seller_id,
      payload.sellerId,
      payload.SellerId,
      payload.PlatformUserId,
      payload.platformUserId,
      shopName,
    ]),
    shopName,
  }
}

function resolveProviderStatus(payload) {
  const rawStatus = normalizeInteger(
    pickFirstNonEmpty([payload.order_status, payload.orderStatus, payload.status]),
  )

  if (rawStatus === 3 || rawStatus === 4) {
    return 'paid'
  }

  if (rawStatus === 6) {
    return 'closed'
  }

  if (rawStatus === 5) {
    return 'refunded'
  }

  const statusText = pickFirstNonEmpty([
    payload.Status,
    payload.status,
    payload.order_status_text,
    payload.orderStatusText,
  ]).toUpperCase()

  if (!statusText) {
    return pickFirstNonEmpty([payload.PayTime, payload.payTime, payload.pay_time]) ? 'paid' : 'unknown'
  }

  if (['WAIT_SELLER_SEND_GOODS', 'WAIT_BUYER_CONFIRM_GOODS', 'TRADE_FINISHED', 'SUCCESS', 'PAID'].includes(statusText)) {
    return 'paid'
  }

  if (['TRADE_CLOSED', 'TRADE_CLOSED_BY_TAOBAO', 'CLOSED'].includes(statusText)) {
    return 'closed'
  }

  if (['REFUND_SUCCESS', 'TRADE_REFUND', 'REFUNDED'].includes(statusText)) {
    return 'refunded'
  }

  if (['WAIT_BUYER_PAY', 'CREATED', 'NEW'].includes(statusText)) {
    return 'unpaid'
  }

  return pickFirstNonEmpty([payload.PayTime, payload.payTime, payload.pay_time]) ? 'paid' : 'unknown'
}

function isTradeFinishedPayload(payload) {
  const rawStatus = normalizeInteger(
    pickFirstNonEmpty([payload?.order_status, payload?.orderStatus, payload?.status]),
  )

  if (rawStatus === 4) {
    return true
  }

  const statusText = pickFirstNonEmpty([
    payload?.Status,
    payload?.status,
    payload?.order_status_text,
    payload?.orderStatusText,
  ]).toUpperCase()

  return statusText === 'TRADE_FINISHED'
}

function normalizeProviderDateTime(value) {
  const normalized = String(value || '').trim()

  if (!normalized) {
    return null
  }

  const isoText = normalized.replace(' ', 'T')
  const utcMatch = isoText.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})$/)

  if (utcMatch) {
    const [, year, month, day, hours, minutes, seconds] = utcMatch
    return new Date(
      Date.UTC(
        Number(year),
        Number(month) - 1,
        Number(day),
        Number(hours) - 8,
        Number(minutes),
        Number(seconds),
      ),
    ).toISOString()
  }

  const date = new Date(normalized)
  return Number.isNaN(date.getTime()) ? null : date.toISOString()
}

function resolveSkuCode(rawKey) {
  const candidates = Array.isArray(rawKey) ? rawKey : [rawKey]

  for (const candidate of candidates) {
    if (typeof candidate === 'string' && candidate.trim()) {
      return candidate.trim()
    }

    if (typeof candidate === 'number' && Number.isFinite(candidate)) {
      return String(candidate)
    }
  }

  return ''
}

function parseExternalSkuDescriptor(rawValue) {
  const raw = String(rawValue || '').trim()
  if (!raw) {
    return {
      raw,
      externalSkuCode: '',
      externalSkuName: '',
    }
  }

  const parts = raw.split('|').map((part) => String(part || '').trim()).filter(Boolean)
  let externalSkuCode = ''
  let externalSkuName = ''

  for (const part of parts) {
    if (!externalSkuCode && !part.includes(':') && !part.includes('：')) {
      externalSkuCode = part
      continue
    }

    const separatorIndex = Math.max(part.indexOf(':'), part.indexOf('：'))
    if (separatorIndex >= 0) {
      const label = part.slice(0, separatorIndex).trim()
      const value = part.slice(separatorIndex + 1).trim()
      if (value && ['商品名称', '商品名', 'sku名称', '规格名称', '名称', '商品'].includes(label)) {
        externalSkuName = value
      }
    }
  }

  if (!externalSkuCode && parts[0]) {
    externalSkuCode = parts[0]
  }

  if (!externalSkuName) {
    externalSkuName = parts
      .map((part) => {
        const separatorIndex = Math.max(part.indexOf(':'), part.indexOf('：'))
        return separatorIndex >= 0 ? part.slice(separatorIndex + 1).trim() : ''
      })
      .find(Boolean) || ''
  }

  return {
    raw,
    externalSkuCode,
    externalSkuName,
  }
}

function normalizeRecord(value) {
  return isPlainObject(value) ? value : {}
}

function normalizeInteger(value) {
  const parsed = Number(value)
  return Number.isFinite(parsed) ? Math.round(parsed) : 0
}

function pickFirstNonEmpty(values) {
  for (const value of values) {
    const normalized = String(value || '').trim()
    if (normalized) {
      return normalized
    }
  }

  return ''
}

function isPlainObject(value) {
  return Object.prototype.toString.call(value) === '[object Object]'
}

function safeParseJson(rawValue) {
  if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue)) {
    return rawValue
  }

  const normalized = String(rawValue || '').trim()

  if (!normalized) {
    return {}
  }

  try {
    const parsed = JSON.parse(normalized)
    return isPlainObject(parsed) ? parsed : {}
  } catch {
    return {}
  }
}
