import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
  isFriendGiftAcceptanceMode,
  normalizeWorkOrderAcceptanceMode,
  normalizeWorkOrderGiftCooldownHours,
  normalizeWorkOrderGiftCooldownMinutes,
} from '../../domain/work-order-acceptance-mode.js'
import {
  createWorkProductMatchLog,
  createWorkOrder,
  createWorkOrderEvent,
  getWorkOrderByOrderItemId,
  listWorkOrdersByPlatformOrderId,
  listWorkProductRuleMappings,
  listWorkProductRules,
  type WorkOrderRow,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
import { randomId } from '../../utils/random.js'
import { nowIso } from '../../utils/time.js'
import { logInfo, logWarn } from '../../utils/logger.js'
import { safeParseJson } from '../admin/admin-query-utils.js'
import { createWorkOrderMaterialAdminNotification } from '../admin/admin-notification-service.js'
import {
  mapWorkOrderAdmin,
  normalizeRequirementFields,
  resolveKuaishouWorkProductMatchContext,
  resolveMatchingProductRuleDecision,
  resolveSkuNameQuantity,
  resolveWorkOrderRulePricing,
  resolveWorkOrderSharingEnabled,
} from './mappers.js'
import { getWorkerProductMatchConfig } from './worker-product-match-config-service.js'

export async function syncWorkerOrdersForSourceOrder(
  order: OrderRow,
  orderItems: OrderItemRow[],
  options: { source?: string; autoOnly?: boolean; sourceMetadata?: JsonObject } = {},
) {
  const [rules, mappings] = await Promise.all([
    listWorkProductRules({ enabled: true }),
    listWorkProductRuleMappings({ enabled: true }),
  ])
  const productMatchConfig = getWorkerProductMatchConfig()
  const created: WorkOrderRow[] = []
  const skipped: Array<{ orderItemId: number; reason: string }> = []
  const decisions: Array<Record<string, unknown>> = []

  for (const item of orderItems) {
    const match = resolveMatchingProductRuleDecision(order, item, rules, mappings, {
      legacyFallbackEnabled: productMatchConfig.legacyFallbackEnabled,
    })
    const matchContext = resolveKuaishouWorkProductMatchContext(item)
    if (matchContext.sellerId) {
      const snapshot = safeParseJson(item.item_snapshot_json)
      await createWorkProductMatchLog({
        orderId: Number(order.id),
        orderItemId: Number(item.id),
        source: options.source || 'source_order',
        sellerId: matchContext.sellerId,
        relItemId: matchContext.relItemId,
        itemTitle: matchContext.itemTitle,
        relSkuId: matchContext.relSkuId,
        skuNick: matchContext.skuNick,
        matchStatus: match.reason,
        ruleId: match.rule?.id || null,
        mappingId: match.mappingId,
        candidatesJson: JSON.stringify(match.candidates),
        rawPayloadJson: JSON.stringify(
          options.sourceMetadata?.kuaishouSendCodeRawPayload ||
            snapshot.kuaishouSendCodeRawPayload ||
            snapshot.kuaishouSendCode ||
            {},
        ),
        now: nowIso(),
      })
    }
    if (!match.rule) {
      const reason = match.reason === 'ambiguous' ? 'rule_match_ambiguous' : 'rule_not_matched'
      skipped.push({
        orderItemId: Number(item.id),
        reason,
      })
      decisions.push(
        buildWorkerConsumerDecision(item, {
          result: 'skipped',
          reason,
          matchReason: match.reason,
          candidates: match.candidates,
        }),
      )
      continue
    }
    const rule = match.rule
    if (options.autoOnly && !rule.auto_create) {
      skipped.push({ orderItemId: Number(item.id), reason: 'auto_create_disabled' })
      decisions.push(
        buildWorkerConsumerDecision(item, {
          result: 'skipped',
          reason: 'auto_create_disabled',
          ruleId: rule.id,
          ruleKey: rule.rule_key,
        }),
      )
      continue
    }
    if (await getWorkOrderByOrderItemId(item.id)) {
      skipped.push({ orderItemId: Number(item.id), reason: 'already_exists' })
      decisions.push(
        buildWorkerConsumerDecision(item, {
          result: 'existing',
          reason: 'already_exists',
          ruleId: rule.id,
          ruleKey: rule.rule_key,
        }),
      )
      continue
    }
    // 订单号跨订单唯一：同一订单的多个 SKU 件允许共享订单号（按件建单是既有设计），
    // 但订单号已挂在其他订单下时跳过，避免自动同步产生撞号工单。
    const samePlatformOrders = await listWorkOrdersByPlatformOrderId(order.platform_order_id)
    if (
      samePlatformOrders.some((existing) => {
        const existingOrderId = Number(existing.order_id || 0)
        return existingOrderId > 0 && existingOrderId !== Number(order.id)
      })
    ) {
      skipped.push({ orderItemId: Number(item.id), reason: 'platform_order_exists' })
      decisions.push(
        buildWorkerConsumerDecision(item, {
          result: 'skipped',
          reason: 'platform_order_exists',
          ruleId: rule.id,
          ruleKey: rule.rule_key,
        }),
      )
      continue
    }

    const fields = normalizeRequirementFields(safeParseJson(rule.requirement_json).fields)
    const skuQuantity = resolveSkuNameQuantity(item.sku_name)
    const { sharingTotalQuantity, sharingUnitReward, rewardAmount } = resolveWorkOrderRulePricing({
      skuQuantity,
      unitPriceFen: Number(rule.unit_price_fen || 0),
      fixedRewardAmount: Number(rule.reward_amount || 0),
      sharingEnabled: rule.sharing_enabled === true,
      sharingAutoFromOrder: rule.sharing_auto_from_order === true,
      sharingTotalQuantity: Number(rule.sharing_total_quantity || 1),
      sharingUnitReward: Number(rule.sharing_unit_reward || 0),
    })
    const sharingEnabled = isFriendGiftAcceptanceMode(rule.acceptance_mode)
      ? false
      : resolveWorkOrderSharingEnabled(rule.sharing_enabled === true, sharingTotalQuantity)
    const now = nowIso()
    const materialComplete = fields.every((field) => !field.required)
    const workOrder = await createWorkOrder({
      workOrderNo: randomId('WO'),
      productRuleId: Number(rule.id),
      orderId: Number(order.id),
      orderItemId: Number(item.id),
      taskId: null,
      platformOrderId: order.platform_order_id,
      productName: item.sku_name || item.sku_code,
      categoryId: rule.category_id,
      status: materialComplete ? WORK_ORDER_STATUS.UNASSIGNED : WORK_ORDER_STATUS.PENDING_MATERIAL,
      rewardAmount,
      requiredDepositAmount: 0,
      depositThresholdAmount: 0,
      sharingEnabled,
      sharingTotalQuantity,
      sharingUnitReward,
      timeoutMinutes: Number(rule.timeout_minutes || 0),
      timeoutPolicy: String(rule.timeout_policy || 'reopen').trim(),
      acceptanceMode: normalizeWorkOrderAcceptanceMode(rule.acceptance_mode),
      giftCooldownHours: normalizeWorkOrderGiftCooldownHours(rule.gift_cooldown_hours),
      giftCooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(rule.gift_cooldown_minutes),
      materialJson: JSON.stringify({
        source: {
          orderId: Number(order.id),
          orderItemId: Number(item.id),
          provider: order.provider,
          platform: order.platform,
          shopId: order.shop_id,
          shopName: order.shop_name,
          skuCode: item.sku_code,
          skuName: item.sku_name,
          skuQuantity,
          quantity: Number(item.quantity || 1),
          orderAmountFen: Number(order.total_amount || 0),
          currency: order.currency || 'CNY',
          syncSource: options.source || 'source_order',
          ...options.sourceMetadata,
        },
      }),
      requirementJson: JSON.stringify({ fields }),
      now,
    })
    if (!workOrder) {
      skipped.push({ orderItemId: Number(item.id), reason: 'create_returned_empty' })
      decisions.push(
        buildWorkerConsumerDecision(item, {
          result: 'failed',
          reason: 'create_returned_empty',
          ruleId: rule.id,
          ruleKey: rule.rule_key,
        }),
      )
      continue
    }

    created.push(workOrder)
    decisions.push(
      buildWorkerConsumerDecision(item, {
        result: 'created',
        reason: 'rule_matched',
        ruleId: rule.id,
        ruleKey: rule.rule_key,
        workOrderId: workOrder.id,
        workOrderNo: workOrder.work_order_no,
        workOrderStatus: workOrder.status,
      }),
    )
    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'system',
      actorId: options.source || 'source_order',
      eventType: 'source_synced',
      fromStatus: '',
      toStatus: workOrder.status,
      payloadJson: JSON.stringify({
        ruleKey: rule.rule_key,
        orderId: order.id,
        orderItemId: item.id,
      }),
      now,
    })
    if (workOrder.status === WORK_ORDER_STATUS.PENDING_MATERIAL) {
      await createWorkOrderMaterialAdminNotification({
        workOrderId: Number(workOrder.id),
        workOrderNo: workOrder.work_order_no,
        productName: workOrder.product_name,
      })
    }
  }

  logInfo('[worker-order-consumer]', '发单平台消费者处理完成', {
    source: options.source || 'source_order',
    orderId: order.id,
    platformOrderId: order.platform_order_id,
    orderItemCount: orderItems.length,
    createdCount: created.length,
    skippedCount: skipped.length,
    decisions,
  })

  const failedDecisions = decisions.filter((decision) => decision.result === 'failed')
  if (failedDecisions.length > 0) {
    logWarn('[worker-order-consumer]', '发单平台消费者存在未成功落库的订单项', {
      source: options.source || 'source_order',
      orderId: order.id,
      platformOrderId: order.platform_order_id,
      decisions: failedDecisions,
    })
  }

  return {
    created: created.map((workOrder) => mapWorkOrderAdmin(workOrder)),
    skipped,
    createdCount: created.length,
    skippedCount: skipped.length,
    decisions,
  }
}

function buildWorkerConsumerDecision(
  item: OrderItemRow,
  detail: Record<string, unknown>,
): Record<string, unknown> {
  const snapshot = safeParseJson(item.item_snapshot_json)
  const sendCode =
    snapshot.kuaishouSendCode &&
    typeof snapshot.kuaishouSendCode === 'object' &&
    !Array.isArray(snapshot.kuaishouSendCode)
      ? (snapshot.kuaishouSendCode as JsonObject)
      : {}

  return {
    orderItemId: Number(item.id),
    skuCode: item.sku_code,
    skuName: item.sku_name,
    quantity: Number(item.quantity || 1),
    sourceItemTitle: String(sendCode.itemTitle || '').trim(),
    sourceSkuNick: String(sendCode.skuNick || '').trim(),
    ...detail,
  }
}
