/**
 * 快手 send-code 数据接入发单平台（工单侧）。
 *
 * 定位：91 回调是订单骨架权威源，快手 send-code 是数据补全源与兜底源。
 * - 订单已存在（91 先到）：回填 shop_id（91 的 productNo 无店铺后缀时）、
 *   补建缺失工单、把凭证信息回填已建工单 material_json
 * - 订单不存在（91 未到/缺失）：用快手数据兜底建单 + 建工单 + 凭证回填
 *
 * 幂等依据：orders 唯一键 provider+platform+shop_id+platform_order_id
 * （由 91 侧查重逻辑保证同 oid 单条记录）、work_orders.order_item_id 唯一索引、
 * listWorkOrdersByPlatformOrderId 查重。
 *
 * 本服务只写 orders / order_items / work_orders，不触碰
 * upsertOrderFromSource / syncDeliveryTasksForOrder / readiness / 回调链路。
 */

import {
  createOrder,
  findLatestOrderByPlatformOrderId,
  updateOrder,
} from '../../repositories/order-repo.js'
import {
  listKuaishouIndustryVoucherWorkOrderSyncSources,
  listKuaishouIndustryVouchersByOid,
} from '../../repositories/kuaishou-industry-voucher-repo.js'
import {
  listOrderItemsByOrderId,
  replaceOrderItems,
  updateOrderItemSourceSnapshot,
} from '../../repositories/order-item-repo.js'
import {
  listWorkOrdersByPlatformOrderId,
  updateWorkOrder,
} from '../../repositories/worker-platform/work-order-repo.js'
import { syncWorkerOrdersForSourceOrder } from './admin-service.js'
import { createWorkOrderEvent } from '../../repositories/worker-platform/work-order-event-repo.js'
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER } from '../open-91/config.js'
import {
  findKuaishouIndustryShopConfig,
  type KuaishouIndustryShopConfig,
} from '../platforms/kuaishou-industry/source-config-service.js'
import { asJsonObject, type JsonObject } from '../../types/json.js'
import type { OrderUpdateInput } from '../../types/repository/inputs.js'
import { nowIso } from '../../utils/time.js'
import type {
  KuaishouIndustryVoucherRow,
  OrderItemRow,
  OrderRow,
} from '../../types/repository/rows.js'

const KUAISHOU_SEND_CODE_SOURCE = 'kuaishou_send_code'
const KUAISHOU_SEND_CODE_ORDER_STATUS = 'paid'

export type SyncWorkOrdersFromSendCodeInput = {
  oid: string
  sellerId: string
  itemId: string
  itemTitle: string
  skuId: string
  num: number
  paymentFen: number
  rawParams: JsonObject
  vouchers: KuaishouIndustryVoucherRow[]
  now: string
}

export type SyncWorkOrdersFromSendCodeResult = {
  order: OrderRow | null
  orderId: number | null
  workOrderIds: number[]
  createdWorkOrderCount: number
  backfilledVoucherCount: number
  skipped: string[]
}

export type KuaishouSendCodeWorkOrderData = {
  sellerId: string
  shopName: string
  itemId: string
  itemTitle: string
  skuId: string
  relItemId: string
  relSkuId: string
  skuNick: string
  quantity: number
  paymentFen: number
}

export async function syncWorkOrdersFromKuaishouSendCode(
  input: SyncWorkOrdersFromSendCodeInput,
): Promise<SyncWorkOrdersFromSendCodeResult> {
  const normalizedOid = String(input.oid || '').trim()
  const skipped: string[] = []
  const sourceData = resolveKuaishouSendCodeWorkOrderData(input)

  if (!normalizedOid) {
    return {
      order: null,
      orderId: null,
      workOrderIds: [],
      createdWorkOrderCount: 0,
      backfilledVoucherCount: 0,
      skipped: ['missing_oid'],
    }
  }

  let order = await findLatestOrderByPlatformOrderId({
    provider: OPEN_91_PROVIDER,
    platform: OPEN_91_PLATFORM,
    platformOrderId: normalizedOid,
  })

  if (order) {
    const orderResult = await backfillOrderShop(order, input, sourceData)
    order = orderResult.order
    if (orderResult.skipped) {
      skipped.push(orderResult.skipped)
    }
  } else {
    const created = await createFallbackOrder(input, sourceData)
    if (created.order) {
      order = created.order
    } else {
      skipped.push(created.reason || 'order_create_failed')
    }
  }

  const workOrderIds: number[] = []
  let createdWorkOrderCount = 0

  if (order) {
    const orderItems = await applyKuaishouSendCodeItemData(
      await listOrderItemsByOrderId(order.id),
      sourceData,
      input.rawParams,
      input.now,
    )

    const syncResult = await syncWorkerOrdersForSourceOrder(order, orderItems, {
      source: KUAISHOU_SEND_CODE_SOURCE,
      autoOnly: true,
      sourceMetadata: {
        kuaishouSendCode: sourceData,
        kuaishouSendCodeRawPayload: input.rawParams,
      },
    })
    createdWorkOrderCount = syncResult.createdCount
    for (const workOrder of syncResult.created) {
      workOrderIds.push(Number(workOrder.workOrderId))
    }
    for (const item of syncResult.skipped) {
      skipped.push(`work_order:${item.reason}`)
    }
  }

  const backfilled = await backfillVouchersToWorkOrders(normalizedOid, input.vouchers, input.now)
  for (const workOrderId of backfilled.workOrderIds) {
    workOrderIds.push(workOrderId)
  }
  if (backfilled.skipped) {
    skipped.push(backfilled.skipped)
  }

  return {
    order,
    orderId: order?.id ?? null,
    workOrderIds,
    createdWorkOrderCount,
    backfilledVoucherCount: backfilled.count,
    skipped,
  }
}

export async function reprocessKuaishouSendCodeWorkOrders(limit = 100) {
  const sources = await listKuaishouIndustryVoucherWorkOrderSyncSources(limit)
  let createdCount = 0
  let skippedCount = 0

  for (const source of sources) {
    const raw = safeParseJson(source.raw_payload_json)
    const body = safeParseJson(raw.body)
    const oid = String(body.oid || source.oid || '').trim()
    if (!oid || !body.sellerId) {
      skippedCount += 1
      continue
    }

    const result = await syncWorkOrdersFromKuaishouSendCode({
      oid,
      sellerId: String(body.sellerId || '').trim(),
      itemId: String(body.itemId || '').trim(),
      itemTitle: String(body.itemTitle || '').trim(),
      skuId: String(body.skuId || '').trim(),
      num: Math.max(1, Number(body.num) || 1),
      paymentFen: normalizePaymentFen(safeParseJson(body.ext).payment),
      rawParams: body,
      vouchers: await listKuaishouIndustryVouchersByOid(oid),
      now: nowIso(),
    })
    createdCount += result.createdWorkOrderCount
    skippedCount += result.skipped.length
  }

  return { scannedCount: sources.length, createdCount, skippedCount }
}

async function backfillOrderShop(
  order: OrderRow,
  input: SyncWorkOrdersFromSendCodeInput,
  sourceData: KuaishouSendCodeWorkOrderData,
): Promise<{ order: OrderRow; skipped?: string }> {
  const sellerId = sourceData.sellerId
  const currentShopId = String(order.shop_id || '').trim()
  const currentShopName = String(order.shop_name || '').trim()

  if (!sellerId) {
    return { order }
  }

  const isPlaceholderShopId = !currentShopId || currentShopId === OPEN_91_PROVIDER
  const hasShopIdConflict = !isPlaceholderShopId && currentShopId !== sellerId

  if (hasShopIdConflict) {
    return { order, skipped: `shop_id_conflict:${currentShopId}` }
  }

  const shouldUpdateShopName = isPlaceholderShopName(currentShopName, sellerId)
  if (currentShopId === sellerId && !shouldUpdateShopName) {
    return { order }
  }

  const updated = await updateOrder(order.id, {
    ...buildOrderUpdateBase(order),
    shopId: sellerId,
    shopName: shouldUpdateShopName ? sourceData.shopName : currentShopName,
    updatedAt: input.now,
  })

  return {
    order: updated || order,
  }
}

function buildOrderUpdateBase(order: OrderRow): Omit<OrderUpdateInput, 'updatedAt'> {
  return {
    provider: String(order.provider || ''),
    platform: String(order.platform || ''),
    shopId: String(order.shop_id || ''),
    shopName: String(order.shop_name || ''),
    platformOrderId: String(order.platform_order_id || ''),
    orderStatus: String(order.order_status || ''),
    payStatus: String(order.pay_status || ''),
    buyerId: String(order.buyer_id || ''),
    buyerName: String(order.buyer_name || ''),
    receiverContact: String(order.receiver_contact || ''),
    totalAmount: Number(order.total_amount) || 0,
    currency: String(order.currency || 'CNY'),
    rawPayloadJson: order.raw_payload_json || '{}',
    paidAt: order.paid_at || null,
  }
}

async function createFallbackOrder(
  input: SyncWorkOrdersFromSendCodeInput,
  sourceData: KuaishouSendCodeWorkOrderData,
): Promise<{
  order: OrderRow | null
  reason?: string
}> {
  const now = input.now
  const { sellerId, itemId, skuNick, paymentFen } = sourceData
  const num = Math.max(1, Number(input.num) || 1)

  if (!itemId && !skuNick) {
    return { order: null, reason: 'order_item_missing' }
  }

  const order = await createOrder({
    provider: OPEN_91_PROVIDER,
    platform: OPEN_91_PLATFORM,
    shopId: sellerId,
    shopName: sourceData.shopName,
    platformOrderId: input.oid,
    orderStatus: KUAISHOU_SEND_CODE_ORDER_STATUS,
    payStatus: 'paid',
    buyerId: '',
    buyerName: '',
    receiverContact: '',
    totalAmount: paymentFen,
    currency: 'CNY',
    rawPayloadJson: {
      source: KUAISHOU_SEND_CODE_SOURCE,
      receivedAt: now,
      body: input.rawParams,
    },
    paidAt: now,
    createdAt: now,
    updatedAt: now,
  })

  if (!order) {
    return { order: null, reason: 'order_create_failed' }
  }

  await replaceOrderItems(order.id, [
    {
      skuCode: itemId,
      skuName: skuNick || sourceData.itemTitle,
      quantity: num,
      specJson: JSON.stringify({
        sellerId,
        skuId: sourceData.skuId,
        itemTitle: sourceData.itemTitle,
        relItemId: sourceData.relItemId,
        relSkuId: sourceData.relSkuId,
        skuNick,
        quantity: sourceData.quantity,
        paymentFen,
        source: KUAISHOU_SEND_CODE_SOURCE,
      }),
      itemSnapshotJson: JSON.stringify({
        source: KUAISHOU_SEND_CODE_SOURCE,
        params: input.rawParams,
        kuaishouSendCode: sourceData,
      }),
      createdAt: now,
      updatedAt: now,
    },
  ])

  return { order }
}

export function resolveKuaishouSendCodeWorkOrderData(
  input: Pick<
    SyncWorkOrdersFromSendCodeInput,
    'sellerId' | 'itemId' | 'itemTitle' | 'skuId' | 'num' | 'paymentFen' | 'rawParams'
  >,
  shops: Array<
    Pick<KuaishouIndustryShopConfig, 'sellerId' | 'shopId' | 'customShopName' | 'shopName'>
  > | null = null,
): KuaishouSendCodeWorkOrderData {
  const sellerId = String(input.sellerId || '').trim()
  const ext = safeParseJson(input.rawParams?.ext)
  const skuNick = String(ext.skuNick || '').trim()
  const paymentFen =
    normalizePaymentFen(input.paymentFen) ||
    normalizePaymentFen(ext.payment ?? ext.totalGoodsValue ?? ext.goodsValue)
  const matchedShop = shops
    ? shops.find((shop) => String(shop.sellerId || shop.shopId || '').trim() === sellerId) || null
    : findKuaishouIndustryShopConfig(sellerId)

  return {
    sellerId,
    shopName: resolveKuaishouSendCodeShopName(sellerId, matchedShop),
    itemId: String(input.itemId || '').trim(),
    itemTitle: String(input.itemTitle || '').trim(),
    skuId: String(input.skuId || '').trim(),
    relItemId: normalizeExternalId(ext.relItemId),
    relSkuId: normalizeExternalId(ext.relSkuId),
    skuNick,
    quantity: Math.max(1, Number(input.num) || 1),
    paymentFen,
  }
}

function normalizePaymentFen(value: unknown): number {
  const amount = Number(value)
  return Number.isFinite(amount) && amount > 0 ? Math.trunc(amount) : 0
}

export function resolveKuaishouSendCodeShopName(
  sellerId: unknown,
  shop: Pick<KuaishouIndustryShopConfig, 'customShopName' | 'shopName'> | null = null,
): string {
  const normalizedSellerId = String(sellerId || '').trim()
  return (
    String(shop?.customShopName || shop?.shopName || '').trim() ||
    (normalizedSellerId ? `快手店铺-${normalizedSellerId}` : '')
  )
}

async function applyKuaishouSendCodeItemData(
  orderItems: OrderItemRow[],
  sourceData: KuaishouSendCodeWorkOrderData,
  rawPayload: JsonObject,
  now: string,
): Promise<OrderItemRow[]> {
  if (!sourceData.skuNick && !sourceData.itemTitle) {
    return orderItems
  }

  const matchedIds = findKuaishouSendCodeItemIds(orderItems, sourceData)
  if (matchedIds.size === 0) {
    return orderItems
  }

  const updatedItems = await Promise.all(
    orderItems.map(async (item) => {
      if (!matchedIds.has(Number(item.id))) {
        return item
      }

      const snapshot = safeParseJson(item.item_snapshot_json)
      const snapshotJson = {
        ...item,
        item_snapshot_json: {
          ...snapshot,
          externalSkuCode: sourceData.skuId || snapshot.externalSkuCode || '',
          externalItemId: sourceData.itemId || snapshot.externalItemId || '',
          externalSkuName: sourceData.skuNick || snapshot.externalSkuName || '',
          externalSkuNameNormalized: sourceData.skuNick || snapshot.externalSkuNameNormalized || '',
          kuaishouSendCode: sourceData,
          kuaishouSendCodeRawPayload: rawPayload,
        },
      }
      const updated = await updateOrderItemSourceSnapshot(item.id, {
        skuName: sourceData.skuNick || item.sku_name,
        itemSnapshotJson: JSON.stringify(snapshotJson.item_snapshot_json),
        updatedAt: now,
      })
      return updated || item
    }),
  )
  return updatedItems
}

function findKuaishouSendCodeItemIds(
  orderItems: OrderItemRow[],
  sourceData: KuaishouSendCodeWorkOrderData,
): Set<number> {
  const identifiers = new Set(
    [sourceData.itemId, sourceData.skuId, sourceData.relItemId, sourceData.relSkuId].filter(
      Boolean,
    ),
  )
  const matched = orderItems.filter((item) => {
    const snapshot = safeParseJson(item.item_snapshot_json)
    return [
      item.sku_code,
      snapshot.externalSkuCode,
      snapshot.externalItemId,
      snapshot.skuId,
      snapshot.itemId,
    ].some((value) => identifiers.has(String(value || '').trim()))
  })

  if (matched.length > 0) {
    return new Set(matched.map((item) => Number(item.id)))
  }

  return orderItems.length === 1 ? new Set([Number(orderItems[0]?.id || 0)]) : new Set()
}

function isPlaceholderShopName(shopName: string, sellerId: string): boolean {
  const normalized = String(shopName || '').trim()
  return !normalized || normalized === '91卡券' || normalized === `快手店铺-${sellerId}`
}

async function backfillVouchersToWorkOrders(
  oid: string,
  vouchers: KuaishouIndustryVoucherRow[],
  now: string,
): Promise<{ workOrderIds: number[]; count: number; skipped?: string }> {
  const workOrders = await listWorkOrdersByPlatformOrderId(oid)
  if (workOrders.length === 0) {
    return { workOrderIds: [], count: 0, skipped: 'work_order_not_found' }
  }

  const voucherItems = vouchers.map((voucher) => ({
    voucherCode: String(voucher.voucher_code || ''),
    token: String(voucher.token || ''),
    eticketType: String(voucher.eticket_type || ''),
    status: String(voucher.status || ''),
    validStartTime: Number(voucher.valid_start_time) || 0,
    validEndTime: Number(voucher.valid_end_time) || 0,
  }))

  const workOrderIds: number[] = []
  let count = 0

  for (const workOrder of workOrders) {
    const material = asJsonObject(safeParseJson(workOrder.material_json))
    const existing = Array.isArray(material.kuaishouIndustryVoucher)
      ? (material.kuaishouIndustryVoucher as unknown[])
      : []
    const existingCodes = new Set(
      existing.map((item) =>
        String((item as JsonObject)?.voucherCode || (item as JsonObject)?.code || ''),
      ),
    )
    const merged = [
      ...existing,
      ...voucherItems.filter((item) => !existingCodes.has(item.voucherCode)),
    ]

    material.kuaishouIndustryVoucher = merged

    const updated = await updateWorkOrder(workOrder.id, {
      material_json: JSON.stringify(material),
      updated_at: now,
    })

    if (!updated) {
      continue
    }

    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'system',
      actorId: KUAISHOU_SEND_CODE_SOURCE,
      eventType: 'voucher_backfilled',
      fromStatus: workOrder.status,
      toStatus: workOrder.status,
      payloadJson: JSON.stringify({
        oid,
        voucherCount: voucherItems.length,
      }),
      now,
    })

    workOrderIds.push(Number(workOrder.id))
    count += 1
  }

  return { workOrderIds, count }
}

function safeParseJson(value: unknown): JsonObject {
  if (value && typeof value === 'object' && !Array.isArray(value)) {
    return value as JsonObject
  }

  try {
    const parsed = JSON.parse(String(value || '{}'))
    return asJsonObject(parsed)
  } catch {
    return {}
  }
}

function normalizeExternalId(value: unknown) {
  const normalized = String(value || '').trim()
  return normalized === '0' ? '' : normalized
}
