import {
  createOrderWithExecutor,
  findLatestOrderByPlatformOrderIdWithExecutor,
  updateOrderWithExecutor,
} from '../../repositories/order-repo.js'
import { replaceOrderItemsWithExecutor } from '../../repositories/order-item-repo.js'
import { withTransaction } from '../../db/client.js'
import { syncDeliveryTasksForOrder } from './delivery-task-service.js'
import { resolveOrderItemForFulfillment } from '../fulfillment/product-resolution-service.js'
import {
  resolveOrderFulfillmentReadiness,
  syncOrderFulfillmentAttachments,
} from '../fulfillment/order-fulfillment-readiness-service.js'
import { syncWorkerOrdersForSourceOrder } from '../worker-platform/index.js'
import {
  publishAdminOrderRealtimeChange,
  publishWorkOrderRealtimeChange,
} from '../realtime/realtime-event-service.js'
import { nowIso } from '../../utils/time.js'
import { logInfo, logIntegration, logWarn } from '../../utils/logger.js'
import { createHttpError } from '../../utils/http.js'
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'

type SourceOrderItem = {
  quantity?: number
  spec?: Record<string, unknown>
  snapshot?: Record<string, unknown>
  [key: string]: unknown
}

type FulfillmentOrderItem = SourceOrderItem & {
  isConfigured: boolean
  skuCode: string
  skuName: string
  quantity: number
  spec?: Record<string, unknown>
  snapshot?: Record<string, unknown>
}

type SourceOrderEvent = {
  provider: string
  platform: string
  shopId: string
  shopName: string
  platformOrderId: string
  orderStatus: string
  payStatus: string
  buyerId: string
  buyerName: string
  receiverContact: string
  totalAmount: number | string
  currency: string
  rawPayload: unknown
  paidAt?: string | null
  items: SourceOrderItem[]
}

type UpsertOrderSourceOptions = {
  sourceLabel?: string
}

type UpsertOrderIgnoredResult = {
  ignored: true
  ignoreReason: string
  order: null
  orderItems: []
  tasks: []
}

type UpsertOrderResult =
  | {
      ignored?: false
      ignoreReason?: string
      order: OrderRow
      orderItems: OrderItemRow[]
      tasks: TaskRow[]
    }
  | UpsertOrderIgnoredResult

type OrderStateInput = {
  order_status?: string
  orderStatus?: string
  pay_status?: string
  payStatus?: string
  paid_at?: string | null
  paidAt?: string | null
}

type OrderStateMergeResult = {
  orderStatus: string
  payStatus: string
  paidAt: string | null
}

type StatusPriorityMap = Record<string, number>

export async function upsertOrderFromSource(
  event: SourceOrderEvent,
  { sourceLabel = 'source' }: UpsertOrderSourceOptions = {},
): Promise<UpsertOrderResult> {
  const now = nowIso()

  logIntegration('[order-service]', `开始处理 ${sourceLabel} 订单 upsert`, {
    provider: event.provider,
    platform: event.platform,
    shopId: event.shopId,
    shopName: event.shopName,
    platformOrderId: event.platformOrderId,
  })

  const resolvedItems = await Promise.all(
    event.items.map((item) =>
      resolveOrderItemForFulfillment({
        provider: event.provider,
        platform: event.platform,
        item,
      }),
    ),
  )
  const resolvedFulfillmentItems = resolvedItems as FulfillmentOrderItem[]
  const configuredItems = resolvedFulfillmentItems.filter((item) => item.isConfigured)

  const persisted = await withTransaction(async (client) => {
    const executor = client.query.bind(client)
    const lockKey = [event.provider, event.platform, event.platformOrderId].join('|')
    await executor('SELECT pg_advisory_xact_lock(hashtextextended($1, 0))', [lockKey])

    const existing = await findLatestOrderByPlatformOrderIdWithExecutor(executor, {
      provider: event.provider,
      platform: event.platform,
      platformOrderId: event.platformOrderId,
    })
    const basePayload = {
      provider: event.provider,
      platform: event.platform,
      shopId: String(existing?.shop_id || event.shopId || '').trim(),
      shopName: String(existing?.shop_name || event.shopName || '').trim(),
      platformOrderId: event.platformOrderId,
      orderStatus: event.orderStatus,
      payStatus: event.payStatus,
      buyerId: event.buyerId,
      buyerName: event.buyerName,
      receiverContact: event.receiverContact,
      totalAmount: event.totalAmount,
      currency: event.currency,
      rawPayloadJson: JSON.stringify(event.rawPayload),
      ...(event.paidAt !== undefined ? { paidAt: event.paidAt } : {}),
    }
    const mergedPayload = mergeSourceOrderState(existing, basePayload)
    const order = existing
      ? await updateOrderWithExecutor(executor, existing.id, {
          ...basePayload,
          ...mergedPayload,
          updatedAt: now,
        })
      : await createOrderWithExecutor(executor, {
          ...basePayload,
          ...mergedPayload,
          createdAt: now,
          updatedAt: now,
        })

    if (!order) {
      throw createHttpError('订单写入失败', {
        statusCode: 500,
        errorCode: 'order_write_failed',
      })
    }

    const orderItems = await replaceOrderItemsWithExecutor(
      executor,
      order.id,
      resolvedFulfillmentItems.map((item) => ({
        skuCode: item.skuCode,
        skuName: item.skuName,
        quantity: item.quantity,
        specJson: JSON.stringify(item.spec || {}),
        itemSnapshotJson: JSON.stringify(item.snapshot || item.spec || {}),
        createdAt: now,
        updatedAt: now,
      })),
    )

    return { order, orderItems }
  })

  const { order, orderItems } = persisted

  const configuredOrderItems = orderItems.filter(isOrderItemConfiguredForFulfillment)
  const readiness =
    configuredOrderItems.length > 0
      ? await resolveOrderFulfillmentReadiness(order)
      : { allowed: true as const, voucherCount: 0, reason: '', blockReason: '' }
  if (!readiness.allowed) {
    logIntegration(
      '[order-service]',
      `${sourceLabel} 订单暂停履约：电子凭证发码回调未确认`,
      {
        orderId: order.id,
        provider: order.provider,
        platform: order.platform,
        platformOrderId: order.platform_order_id,
        voucherCount: readiness.voucherCount,
        reason: readiness.reason,
      },
      { level: 'warn' },
    )

    const workOrderSync = await syncWorkerOrdersForSourceOrder(order, orderItems, {
      source: `${sourceLabel}_order_upsert`,
      autoOnly: true,
    })
    logInfo('[order-consumer-router]', '来源订单消费者分流完成', {
      source: sourceLabel,
      orderId: order.id,
      platformOrderId: order.platform_order_id,
      fulfillment: {
        result: 'blocked',
        reason: readiness.blockReason,
        detail: readiness.reason,
        orderItemIds: configuredOrderItems.map((item) => item.id),
      },
      workerPlatform: {
        createdCount: workOrderSync.createdCount,
        skippedCount: workOrderSync.skippedCount,
        decisions: workOrderSync.decisions,
      },
    })
    publishSourceOrderRealtimeChanges(order.id, workOrderSync.created)
    return {
      ignoreReason: readiness.blockReason || 'fulfillment_not_ready',
      order,
      orderItems,
      tasks: [],
    }
  }

  const tasks =
    configuredOrderItems.length > 0
      ? await syncDeliveryTasksForOrder(order, configuredOrderItems)
      : []
  await syncOrderFulfillmentAttachments(order, tasks, {
    source: `${sourceLabel}_order_upsert`,
    now,
  })
  const workOrderSync = await syncWorkerOrdersForSourceOrder(order, orderItems, {
    source: `${sourceLabel}_order_upsert`,
    autoOnly: true,
  })
  logOrderConsumerOutcome({
    sourceLabel,
    order,
    orderItems,
    configuredOrderItems,
    tasks,
    workerDecisions: workOrderSync.decisions,
    workerCreatedCount: workOrderSync.createdCount,
    workerSkippedCount: workOrderSync.skippedCount,
  })
  publishSourceOrderRealtimeChanges(order.id, workOrderSync.created)

  logIntegration('[order-service]', `${sourceLabel} 订单 upsert 完成`, {
    orderId: order.id,
    provider: order.provider,
    platform: order.platform,
    shopId: order.shop_id,
    shopName: order.shop_name,
    platformOrderId: order.platform_order_id,
    orderItemCount: orderItems.length,
    taskCount: tasks.length,
    resolvedSkuCodes: configuredItems.map((item) => item.skuCode),
  })

  return {
    order,
    orderItems,
    tasks,
  }
}

function publishSourceOrderRealtimeChanges(
  orderId: number,
  workOrders: Array<{ workOrderId: number }> = [],
) {
  publishAdminOrderRealtimeChange(Number(orderId))
  for (const workOrder of workOrders) {
    publishWorkOrderRealtimeChange({ workOrderId: workOrder.workOrderId })
  }
}

function logOrderConsumerOutcome({
  sourceLabel,
  order,
  orderItems,
  configuredOrderItems,
  tasks,
  workerDecisions,
  workerCreatedCount,
  workerSkippedCount,
}: {
  sourceLabel: string
  order: OrderRow
  orderItems: OrderItemRow[]
  configuredOrderItems: OrderItemRow[]
  tasks: TaskRow[]
  workerDecisions: Array<Record<string, unknown>>
  workerCreatedCount: number
  workerSkippedCount: number
}) {
  const configuredItemIds = new Set(configuredOrderItems.map((item) => Number(item.id)))
  const taskCountByOrderItemId = new Map<number, number>()
  for (const task of tasks) {
    const orderItemId = Number(task.order_item_id || 0)
    taskCountByOrderItemId.set(orderItemId, (taskCountByOrderItemId.get(orderItemId) || 0) + 1)
  }

  const missingFulfillmentItems = configuredOrderItems
    .filter(
      (item) =>
        (taskCountByOrderItemId.get(Number(item.id)) || 0) <
        Math.max(1, Number(item.quantity || 1)),
    )
    .map((item) => ({
      orderItemId: item.id,
      skuCode: item.sku_code,
      skuName: item.sku_name,
      expectedTaskCount: Math.max(1, Number(item.quantity || 1)),
      actualTaskCount: taskCountByOrderItemId.get(Number(item.id)) || 0,
      route: resolveOrderItemRouteDiagnostic(item),
    }))
  const workerAcceptedItemIds = new Set(
    workerDecisions
      .filter((decision) => decision.result === 'created' || decision.result === 'existing')
      .map((decision) => Number(decision.orderItemId || 0))
      .filter((orderItemId) => orderItemId > 0),
  )
  const dualConsumedOrderItemIds = Array.from(workerAcceptedItemIds).filter((orderItemId) =>
    configuredItemIds.has(orderItemId),
  )
  const unhandledOrderItems = orderItems
    .filter((item) => {
      const orderItemId = Number(item.id)
      return !configuredItemIds.has(orderItemId) && !workerAcceptedItemIds.has(orderItemId)
    })
    .map((item) => ({
      orderItemId: item.id,
      skuCode: item.sku_code,
      skuName: item.sku_name,
    }))

  const detail = {
    source: sourceLabel,
    orderId: order.id,
    platformOrderId: order.platform_order_id,
    fulfillment: {
      configuredOrderItemIds: Array.from(configuredItemIds),
      taskIds: tasks.map((task) => task.id),
      taskCount: tasks.length,
      missingItems: missingFulfillmentItems,
    },
    workerPlatform: {
      createdCount: workerCreatedCount,
      skippedCount: workerSkippedCount,
      decisions: workerDecisions,
    },
    dualConsumedOrderItemIds,
    unhandledOrderItems,
  }

  logInfo('[order-consumer-router]', '来源订单消费者分流完成', detail)
  if (missingFulfillmentItems.length > 0) {
    logWarn('[order-consumer-router]', '已配置履约的订单项存在任务缺口', detail)
  }
  if (dualConsumedOrderItemIds.length > 0) {
    logWarn('[order-consumer-router]', '同一订单项被履约与发单平台消费者同时接收', detail)
  }
  if (unhandledOrderItems.length > 0) {
    logWarn('[order-consumer-router]', '订单项未被履约或发单平台消费者接收', detail)
  }
}

function resolveOrderItemRouteDiagnostic(item: OrderItemRow) {
  const snapshot = parseOrderItemSnapshot(item.item_snapshot_json) || {}
  const sendCode =
    snapshot.kuaishouSendCode &&
    typeof snapshot.kuaishouSendCode === 'object' &&
    !Array.isArray(snapshot.kuaishouSendCode)
      ? (snapshot.kuaishouSendCode as Record<string, unknown>)
      : {}
  const route =
    snapshot.fulfillmentRoute &&
    typeof snapshot.fulfillmentRoute === 'object' &&
    !Array.isArray(snapshot.fulfillmentRoute)
      ? (snapshot.fulfillmentRoute as Record<string, unknown>)
      : {}

  return {
    snapshotIsConfigured: snapshot.isConfigured === true,
    selectedExecutorKey: String(route.selectedExecutorKey || '').trim(),
    selectedRuleId: String(route.selectedRuleId || '').trim(),
    reason: String(route.reason || '').trim(),
    sourceItemTitle: String(sendCode.itemTitle || '').trim(),
    sourceSkuNick: String(sendCode.skuNick || '').trim(),
    candidates: Array.isArray(route.candidates) ? route.candidates : [],
    skipped: Array.isArray(route.skipped) ? route.skipped : [],
  }
}

const ORDER_STATUS_PRIORITY = {
  created: 0,
  paid: 1,
  closed: 2,
  refunded: 3,
}

const PAY_STATUS_PRIORITY = {
  unpaid: 0,
  failed: 0,
  paid: 1,
  refunded: 2,
}

export function mergeSourceOrderState(
  existing: OrderStateInput | null | undefined,
  incoming: OrderStateInput | null | undefined,
): OrderStateMergeResult {
  const orderStatus =
    chooseHigherPriorityStatus(
      normalizeStateValue(existing?.order_status ?? existing?.orderStatus),
      normalizeStateValue(incoming?.orderStatus ?? incoming?.order_status),
      ORDER_STATUS_PRIORITY,
    ) ||
    normalizeStateValue(incoming?.orderStatus ?? incoming?.order_status) ||
    'created'

  const payStatus =
    chooseHigherPriorityStatus(
      normalizeStateValue(existing?.pay_status ?? existing?.payStatus),
      normalizeStateValue(incoming?.payStatus ?? incoming?.pay_status),
      PAY_STATUS_PRIORITY,
    ) ||
    normalizeStateValue(incoming?.payStatus ?? incoming?.pay_status) ||
    'unpaid'

  return {
    orderStatus,
    payStatus,
    paidAt: resolveMergedPaidAt({
      existingPaidAt: existing?.paid_at ?? existing?.paidAt ?? null,
      incomingPaidAt: incoming?.paidAt ?? incoming?.paid_at ?? null,
      payStatus,
    }),
  }
}

export function isOrderItemConfiguredForFulfillment(item: OrderItemRow): boolean {
  const rawSnapshot = item.item_snapshot_json
  const snapshot =
    rawSnapshot && typeof rawSnapshot === 'object' && !Array.isArray(rawSnapshot)
      ? rawSnapshot
      : parseOrderItemSnapshot(rawSnapshot)

  return Boolean(snapshot && snapshot.isConfigured === true)
}

function parseOrderItemSnapshot(value: unknown): Record<string, unknown> | null {
  try {
    const parsed = JSON.parse(String(value || '{}'))
    return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
      ? (parsed as Record<string, unknown>)
      : null
  } catch {
    return null
  }
}

function chooseHigherPriorityStatus(
  existingValue: string,
  incomingValue: string,
  priorityMap: StatusPriorityMap,
): string {
  const existingPriority = resolveStatusPriority(existingValue, priorityMap)
  const incomingPriority = resolveStatusPriority(incomingValue, priorityMap)

  if (incomingPriority > existingPriority) {
    return incomingValue
  }

  if (existingPriority >= incomingPriority) {
    return existingValue
  }

  return incomingValue || existingValue
}

function resolveStatusPriority(value: string, priorityMap: StatusPriorityMap): number {
  return Number(priorityMap[normalizeStateValue(value)] ?? -1)
}

function normalizeStateValue(value: unknown): string {
  return String(value || '')
    .trim()
    .toLowerCase()
}

function resolveMergedPaidAt({
  existingPaidAt,
  incomingPaidAt,
  payStatus,
}: {
  existingPaidAt: string | null
  incomingPaidAt: string | null
  payStatus: string
}): string | null {
  if (!['paid', 'refunded'].includes(normalizeStateValue(payStatus))) {
    return null
  }

  const existingTime = parseDateValue(existingPaidAt)
  const incomingTime = parseDateValue(incomingPaidAt)

  if (existingTime && incomingTime) {
    return existingTime <= incomingTime ? existingPaidAt : incomingPaidAt
  }

  return existingPaidAt || incomingPaidAt || null
}

function parseDateValue(value: unknown): number | null {
  const text = String(value || '').trim()

  if (!text) {
    return null
  }

  const timestamp = Date.parse(text)
  return Number.isFinite(timestamp) ? timestamp : null
}
