import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { updateTask } from '../../../repositories/task-repo.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { TASK_STATUS, normalizeTaskStatus } from '../../../domain/task-status.js'
import type { TaskRow } from '../../../types/repository/rows.js'
import { getClaimIdentityFromTask } from '../../claim/claim-identity.js'
import {
  buildKuaishouCloudShippedSnapshot,
  isIndustryEVoucherTask,
  isKuaishouCloudTask,
  maskCode,
  maskPhone,
  normalizeKuaishouCloudFlow,
  type JsonObject,
} from './domain.js'
import { resolvePersistedCloudtentaclesContextBySourceKeys } from './cloudtentacles-context.js'
import { syncKuaishouCloudRoleInfoBeforeDispatch } from './dispatch-role-sync.js'
import { markKuaishouCloudDispatchFailed } from './dispatch-failure.js'
import {
  prepareStockAndDispatch,
  resolveCloudSkuDispatchLockKeys,
  withCloudSkuDispatchLocks,
} from './dispatch-stock.js'
import {
  resolveDispatchDeliveryItems,
  type DispatchResultItem,
  type DispatchStockResult,
} from './dispatch-types.js'
import { returnKuaishouCloudFulfillmentTask } from './return-fulfillment.js'
import { normalizeActor, parseTaskContext } from './task-context.js'

/**
 * lewan 自动/后台发货主用例：
 * UID 闸门同步角色 → 库存与采购 → cloudtentacles 下发 → 可选自动退号收尾。
 */
export async function dispatchKuaishouCloudFulfillmentTask(
  task: TaskRow,
  options: JsonObject = {},
) {
  if (!isKuaishouCloudTask(task)) {
    throw createHttpError('当前任务不是 kuaishou-lewan 履约任务', {
      statusCode: 409,
      errorCode: 'kuaishou_cloud_task_invalid',
    })
  }

  const actor = normalizeActor(options.actor)
  const now = nowIso()
  const taskContext = parseTaskContext(task)
  const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
  const cloudContext = resolvePersistedCloudtentaclesContextBySourceKeys([
    flow.binding.resolvedSourceKey,
    ...flow.binding.cloudSourceKeys,
  ])

  if (!flow.binding.skuId || !flow.binding.vnId || !flow.binding.vnPhone) {
    throw createHttpError('当前任务还没有准备好绑定资源，请先完成绑定资源准备', {
      statusCode: 409,
      errorCode: 'kuaishou_cloud_not_prepared',
    })
  }

  const persistedTicketCode = String(flow.ticket.code || '').trim()
  const voucherContext = isPlainObject(taskContext.kuaishouIndustryVoucher)
    ? taskContext.kuaishouIndustryVoucher
    : {}
  const industryVoucherCode = String(
    voucherContext.voucherCode || voucherContext.eticketId || '',
  ).trim()
  const hasIndustryVoucherForDispatch = Boolean(industryVoucherCode) || isIndustryEVoucherTask(task)
  const resolvedTicketCode = persistedTicketCode || industryVoucherCode

  if (!resolvedTicketCode && !hasIndustryVoucherForDispatch) {
    throw createHttpError('旧快手小店核销流程已停用，请改用行业电子凭证处理', {
      statusCode: 409,
      errorCode: 'kuaishou_cloud_missing_ticket_code',
    })
  }

  if (
    flow.dispatch.status === 'success' &&
    normalizeTaskStatus(task.task_status) === TASK_STATUS.DISPATCHED_PENDING_RETURN
  ) {
    return { task, flow }
  }

  const synced = await syncKuaishouCloudRoleInfoBeforeDispatch(task, {
    now,
    actor,
    source: options.source || 'system_before_dispatch',
    cloudContext,
    taskContext,
    flow,
  })
  const syncedFlow = synced.flow
  const syncedTaskContext = synced.taskContext

  const deliveryItems = resolveDispatchDeliveryItems(syncedFlow as JsonObject)
  if (deliveryItems.length === 0) {
    throw createHttpError('当前任务缺少 cloud 发货物品配置', {
      statusCode: 409,
      errorCode: 'kuaishou_cloud_missing_delivery_items',
    })
  }

  let dispatchResults: DispatchResultItem[]
  let stockResult: DispatchStockResult
  try {
    ;({ dispatchResults, stockResult } = await withCloudSkuDispatchLocks(
      resolveCloudSkuDispatchLockKeys(cloudContext.resolvedSourceKey, deliveryItems),
      () =>
        prepareStockAndDispatch({
          task,
          flow: syncedFlow as JsonObject,
          cloudContext,
          deliveryItems,
        }),
    ))
  } catch (error) {
    await markKuaishouCloudDispatchFailed(
      task,
      syncedTaskContext as JsonObject,
      syncedFlow as JsonObject,
      error,
      {
        actor,
        source: options.source || 'system',
      },
    )
    throw error
  }

  const firstDispatchResult: DispatchResultItem = dispatchResults[0] || {
    cloudSkuId: syncedFlow.binding.skuId,
    cloudSkuName: syncedFlow.binding.skuName,
    quantity: 1,
    unitIndex: 1,
    sendType: 0,
    note: '',
    responseMessage: '',
  }
  const dispatchSummary =
    dispatchResults.length > 1
      ? `cloudtentacles 发货成功，共 ${dispatchResults.length} 次`
      : String(
          firstDispatchResult.responseMessage ||
            firstDispatchResult.note ||
            'cloudtentacles 发货成功',
        ).trim()

  const claimIdentity = getClaimIdentityFromTask(synced.task || task)
  const shippedSnapshot = buildKuaishouCloudShippedSnapshot({
    expectedUid: claimIdentity.expectedUid,
    roleId: syncedFlow.binding.roleId || syncedFlow.role.rid,
    roleName: syncedFlow.binding.roleName || syncedFlow.role.name,
    vnId: syncedFlow.binding.vnId,
    vnPhone: syncedFlow.binding.vnPhone,
    vnKey: syncedFlow.binding.vnKey,
    dispatchedAt: now,
  })

  const nextContext = {
    ...syncedTaskContext,
    kuaishouCloudFulfillment: {
      ...syncedFlow,
      ticket: {
        ...syncedFlow.ticket,
        code: resolvedTicketCode,
        capturedAt: resolvedTicketCode
          ? syncedFlow.ticket.capturedAt || now
          : syncedFlow.ticket.capturedAt,
        capturedBy: syncedFlow.ticket.capturedBy,
      },
      dispatch: {
        ...syncedFlow.dispatch,
        status: 'success',
        dispatchAt: now,
        dispatchBy: actor,
        sendType: Number(firstDispatchResult.sendType || 0) || 0,
        note: dispatchSummary,
        items: dispatchResults,
      },
      // 冻结发货身份：后续 claim 轮询/过期换号不得改写展示与匹配依据
      shipped: syncedFlow.shipped || shippedSnapshot,
      purchase: {
        ...syncedFlow.purchase,
        usedKnapsack: stockResult.usedKnapsack,
        purchaseTriggered: stockResult.purchaseTriggered,
        assetBefore: stockResult.assetBefore,
        assetAfter: stockResult.assetAfter,
        purchaseAt: stockResult.purchaseTriggered ? now : syncedFlow.purchase.purchaseAt,
        items: stockResult.items,
      },
    },
  }

  let updatedTask = await updateTask(task.id, {
    task_status: TASK_STATUS.DISPATCHED_PENDING_RETURN,
    delivery_status: 'delivered',
    result_code: 'kuaishou_cloud_dispatched',
    result_message: dispatchSummary,
    user_action_status: 'not_required',
    last_error: '',
    context_json: JSON.stringify(nextContext),
    updated_at: now,
  })
  if (!updatedTask) {
    throw createHttpError('kuaishou-lewan 发货状态更新失败', {
      statusCode: 500,
      errorCode: 'kuaishou_cloud_dispatch_update_failed',
    })
  }

  await createTaskEvent(
    task.id,
    'kuaishou_cloud_dispatched',
    {
      source: String(options.source || 'system').trim() || 'system',
      ticketCodeMasked: maskCode(resolvedTicketCode),
      skuId: syncedFlow.binding.skuId,
      vnId: syncedFlow.binding.vnId,
      vnPhoneMasked: maskPhone(syncedFlow.binding.vnPhone),
      expectedUid: shippedSnapshot.expectedUid,
      roleId: shippedSnapshot.roleId,
      roleName: shippedSnapshot.roleName,
      sendType: firstDispatchResult.sendType,
      note: dispatchSummary,
      deliveryItems,
      dispatchResults,
      stockResult,
      shipped: shippedSnapshot,
      actor,
    },
    now,
  )

  const shouldAutoFinalize =
    options.autoFinalize === true &&
    normalizeKuaishouCloudFlow(nextContext.kuaishouCloudFulfillment).returnNumber
      .autoReturnEnabled === true

  if (shouldAutoFinalize) {
    const finalizeResult = await returnKuaishouCloudFulfillmentTask(updatedTask, {
      actor,
      source: options.source || 'system_auto_finalize',
      // 发货后自动收尾：退号并尝试核销（与 admin 清理退号不同）
      consumeIndustryVoucher: true,
    })
    updatedTask = finalizeResult.task
  }

  return {
    task: updatedTask,
    flow: normalizeKuaishouCloudFlow(parseTaskContext(updatedTask).kuaishouCloudFulfillment),
  }
}

function isPlainObject(value: unknown): value is JsonObject {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
}
