import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { listTasksByOrderId, updateTask } from '../../../repositories/task-repo.js'
import { createHttpError } from '../../../utils/http.js'
import { logIntegration } from '../../../utils/logger.js'
import { parseTaskContext } from '../../../utils/task-json.js'
import { nowIso } from '../../../utils/time.js'
import { TASK_STATUS } from '../../../domain/task-status.js'
import { getClaimIdentityFromContext } from '../../claim/claim-identity.js'
import type { JsonObject } from '../../../types/json.js'
import {
  createAffiliateDashOrder,
  getAffiliateDashOrder,
  getAffiliateDashWallet,
  type AffiliateDashOrder,
} from '../../platforms/affiliate-dash/order-service.js'
import { getAffiliateDashConfig } from '../../platforms/affiliate-dash/config.js'
import { consumeKuaishouIndustryVouchersForTask } from '../../platforms/kuaishou-industry/voucher-service.js'
import { buildKuaishouIndustryVoucherContext } from '../../platforms/kuaishou-industry/voucher-binding-service.js'
import type { TaskRow } from '../../../types/repository/rows.js'

export function isAffiliateDashTask(task: Partial<TaskRow> | null | undefined) {
  return String(task?.executor_key || '').trim() === 'affiliate_dash'
}

/**
 * affiliate_dash 履约任务：下单建单（preparePaidTask）→ 用户在统一领取页完成
 * delivery/bind/submit（阶段 4）→ 回调 order.shipping.updated 驱动状态（阶段 5）。
 */
export async function prepareAffiliateDashTask(task: TaskRow) {
  if (!isAffiliateDashTask(task)) {
    throw createHttpError('当前任务不是 affiliate-dash 履约任务', {
      statusCode: 409,
      errorCode: 'affiliate_dash_task_invalid',
    })
  }

  const now = nowIso()
  const taskContext = parseTaskContext(task)
  const flow = normalizeAffiliateDashFlow(taskContext.affiliateDash)

  // 幂等：已建单直接收敛到 link_generated（不重复扣款）
  if (flow.orderNo) {
    return updateTask(task.id, {
      task_status: TASK_STATUS.LINK_GENERATED,
      user_action_status: 'pending_claim',
      context_json: JSON.stringify({
        ...taskContext,
        affiliateDash: flow,
      }),
      updated_at: now,
    })
  }

  if (!flow.sku) {
    throw createHttpError(
      'affiliate-dash 商品 sku 缺失，请配置 91 商品 → affiliate_dash sku 映射',
      {
        statusCode: 409,
        errorCode: 'affiliate_dash_sku_missing',
      },
    )
  }

  const siblingTasks = await listTasksByOrderId(task.order_id)
  const clientOrderNo = buildAffiliateDashClientOrderNo(task, siblingTasks)
  const data = buildAffiliateDashOrderData(task, taskContext)
  const buyerReference = String(task.platform_order_id || task.task_no || '').trim()

  // 余额预检：钱包余额不足提前拦截（避免建单 400 后才降级）；预检失败不阻塞下单
  await preflightAffiliateDashWallet(flow.sku)

  const order = await createAffiliateDashOrder({
    clientOrderNo,
    sku: flow.sku,
    buyerReference: buyerReference || undefined,
    data: Object.keys(data).length ? data : undefined,
  })

  const nextFlow = mergeAffiliateDashOrder(flow, order, {
    clientOrderNo,
    syncedAt: now,
  })

  // 核销时机优化：建单成功（91 卡信息到手、领取链接可发放）即核销行业电子凭证，
  // 不再等 delivered 回调（参考 kuaishou-feifei「给用户链接即核销」）。
  // 核销失败不阻塞下单与链接发放：consumeStatus=failed，delivered 回调兜底补核销。
  const consumeResult = await consumeKuaishouIndustryVouchersForTask(task, {
    source: 'affiliate_dash_order_created',
    consumeTime: Date.now(),
  })
  const consumedVoucher = consumeResult.consumed[0] || null
  let nextIndustryVoucher = taskContext.kuaishouIndustryVoucher
  if (consumeResult.vouchers.length > 0) {
    nextFlow.consumeStatus = consumeResult.ok ? 'success' : 'failed'
    if (consumedVoucher) {
      nextIndustryVoucher = buildKuaishouIndustryVoucherContext(
        consumedVoucher,
        taskContext.kuaishouIndustryVoucher,
        now,
      )
    }
    if (!consumeResult.ok) {
      logIntegration(
        '[affiliate-dash]',
        '建单成功但电子凭证核销失败，delivered 回调将兜底重试',
        {
          taskId: task.id,
          orderNo: order.orderNo,
          voucherCount: consumeResult.vouchers.length,
          failedCount: consumeResult.failed.length,
          errorMessage: consumeResult.failed[0]?.errorMessage || '',
        },
        { level: 'warn' },
      )
    }
  } else {
    nextFlow.consumeStatus = 'not_required'
  }

  const updatedTask = await updateTask(task.id, {
    task_status: TASK_STATUS.LINK_GENERATED,
    user_action_status: 'pending_claim',
    result_code: 'affiliate_dash_order_created',
    result_message: 'affiliate-dash 订单已创建',
    context_json: JSON.stringify({
      ...taskContext,
      affiliateDash: nextFlow,
      kuaishouIndustryVoucher: nextIndustryVoucher,
    }),
    updated_at: now,
  })

  await createTaskEvent(
    task.id,
    'affiliate_dash_order_created',
    {
      orderNo: order.orderNo,
      clientOrderNo,
      sku: flow.sku,
      amount: order.amount,
      currency: order.currency,
      orderStatus: order.orderStatus,
      canShip: order.canShip,
    },
    now,
  )

  logIntegration('[affiliate-dash]', 'affiliate-dash 订单已创建', {
    taskId: task.id,
    orderNo: order.orderNo,
    clientOrderNo,
    sku: flow.sku,
    amount: order.amount,
    currency: order.currency,
  })

  return updatedTask
}

/**
 * 状态合并（回调 / 主动对账共用，可重入）：
 * paid → link_generated；delivering → redeeming；
 * delivered → 核销行业电子凭证 → redeemed / manual_review；
 * ship_failed → retry_pending；cancelled → closed。
 */
export async function syncAffiliateDashTaskStatus(
  task: TaskRow,
  options: { snapshotOnly?: boolean } = {},
) {
  if (!isAffiliateDashTask(task)) {
    return task
  }

  const taskContext = parseTaskContext(task)
  const flow = normalizeAffiliateDashFlow(taskContext.affiliateDash)
  if (!flow.orderNo) {
    return task
  }

  const now = nowIso()
  // dev-mock 任务或 snapshotOnly（如 submit 已拿到 delivered）不请求 affiliate-dash 平台，
  // 直接用本地快照（flow 自身）收敛状态。
  const useSnapshot = Boolean(flow.mock?.enabled) || options.snapshotOnly
  const order = useSnapshot
    ? ({
        orderNo: flow.orderNo,
        orderStatus: flow.orderStatus,
        failureReason: flow.failureReason,
        canShip: flow.canShip,
        raw: null,
      } as unknown as AffiliateDashOrder)
    : await getAffiliateDashOrder(flow.orderNo)
  let nextTaskStatus = task.task_status
  let deliveryStatus = task.delivery_status
  let redeemedAt = task.redeemed_at
  let resultCode = task.result_code
  let resultMessage = task.result_message
  let lastError = task.last_error
  const nextFlow = mergeAffiliateDashOrder(flow, order, { syncedAt: now })
  const nextIndustryVoucher = taskContext.kuaishouIndustryVoucher

  switch (order.orderStatus) {
    case 'paid':
      break
    case 'delivering':
      nextTaskStatus = TASK_STATUS.REDEEMING
      deliveryStatus = 'delivering'
      resultCode = 'affiliate_dash_delivering'
      resultMessage = order.failureReason || 'affiliate-dash 发货处理中'
      lastError = ''
      break
    case 'delivered': {
      const alreadyConsumed =
        nextFlow.consumeStatus === 'success' || nextFlow.consumeStatus === 'not_required'
      const consumeResult = alreadyConsumed
        ? { ok: true, vouchers: [], consumed: [], failed: [] }
        : await consumeKuaishouIndustryVouchersForTask(task, {
            source: 'affiliate_dash_delivered',
            consumeTime: Date.now(),
          })
      if (consumeResult.ok || consumeResult.vouchers.length === 0) {
        nextTaskStatus = TASK_STATUS.REDEEMED
        deliveryStatus = 'delivered'
        redeemedAt = redeemedAt || now
        resultCode = 'affiliate_dash_delivered'
        resultMessage = 'affiliate-dash 履约成功'
        lastError = ''
        nextFlow.consumeStatus = consumeResult.vouchers.length > 0 ? 'success' : 'not_required'
        logIntegration('[affiliate-dash]', 'affiliate-dash 履约完成，行业电子凭证核销完成', {
          taskId: task.id,
          orderNo: flow.orderNo,
          voucherCount: consumeResult.vouchers.length,
          consumedCount: consumeResult.consumed.length,
          consumeStatus: nextFlow.consumeStatus,
        })
      } else {
        nextTaskStatus = TASK_STATUS.MANUAL_REVIEW
        resultCode = 'affiliate_dash_industry_consume_failed'
        resultMessage = consumeResult.failed[0]?.errorMessage || '电子凭证核销失败，请人工处理'
        lastError = resultMessage
        nextFlow.consumeStatus = 'failed'
        logIntegration(
          '[affiliate-dash]',
          'affiliate-dash 履约完成但核销失败',
          {
            taskId: task.id,
            orderNo: flow.orderNo,
            errorMessage: resultMessage,
          },
          { level: 'warn' },
        )
      }
      break
    }
    case 'ship_failed':
      nextTaskStatus = TASK_STATUS.RETRY_PENDING
      resultCode = 'affiliate_dash_ship_failed'
      resultMessage = order.failureReason || 'affiliate-dash 发货失败，可重试'
      lastError = resultMessage
      break
    case 'cancelled':
      nextTaskStatus = TASK_STATUS.CLOSED
      resultCode = 'affiliate_dash_cancelled'
      resultMessage = order.failureReason || 'affiliate-dash 订单已取消'
      lastError = ''
      break
    default:
      break
  }

  const isAlreadyTerminal = (
    [
      TASK_STATUS.REDEEMED,
      TASK_STATUS.MANUAL_REVIEW,
      TASK_STATUS.CLOSED,
      TASK_STATUS.FAILED,
    ] as string[]
  ).includes(task.task_status)
  // 终态保护：已收敛成功的任务，非 delivered 状态不允许降级（如轮询时平台详情短暂返回
  // delivering/paid 会把 REDEEMED 打回 REDEEMING，导致结果页闪烁/倒退）。
  const shouldApply = !isAlreadyTerminal || order.orderStatus === 'delivered'
  if (!shouldApply) {
    return task
  }

  const updatedTask = await updateTask(task.id, {
    task_status: nextTaskStatus,
    delivery_status: deliveryStatus,
    redeemed_at: redeemedAt,
    result_code: resultCode,
    result_message: resultMessage,
    last_error: lastError,
    context_json: JSON.stringify({
      ...taskContext,
      affiliateDash: nextFlow,
      kuaishouIndustryVoucher: nextIndustryVoucher,
    }),
    updated_at: now,
  })

  return updatedTask || task
}

export type AffiliateDashFlow = {
  flowType: 'affiliate_dash'
  sku: string
  productName: string
  orderNo: string
  clientOrderNo: string
  orderStatus: string
  canShip: boolean
  cannotShipReason: string
  providerOrderNo: string
  failureReason: string
  amount: number
  currency: string
  /** 阶段 4 交付交互数据（bind/submit） */
  bindUuid: string
  bindUrl: string
  qrUrl: string
  gameAccount: string
  expectedGameAccount: string
  bindMismatch: boolean
  /** 是否已在 affiliate-dash 侧完成绑定（bind-result.bound） */
  bound: boolean
  boundAccount: string
  gameChannel: string
  submitStatus: string
  consumeStatus: string
  lastSyncedAt: unknown
  raw: unknown
  /** dev-mock 标记：enabled 时所有 affiliate-dash 平台调用短路（建单/绑定/提交/同步均不请求外部） */
  mock: { enabled: boolean; orderNo: string; createdAt: string } | null
}

export function normalizeAffiliateDashFlow(value: unknown): AffiliateDashFlow {
  const source =
    value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonObject) : {}

  return {
    flowType: 'affiliate_dash',
    sku: String(source.sku || '').trim(),
    productName: String(source.productName || '').trim(),
    orderNo: String(source.orderNo || '').trim(),
    clientOrderNo: String(source.clientOrderNo || '').trim(),
    orderStatus: String(source.orderStatus || '').trim(),
    canShip: Boolean(source.canShip),
    cannotShipReason: String(source.cannotShipReason || '').trim(),
    providerOrderNo: String(source.providerOrderNo || '').trim(),
    failureReason: String(source.failureReason || '').trim(),
    amount: Number(source.amount || 0) || 0,
    currency: String(source.currency || '').trim(),
    bindUuid: String(source.bindUuid || '').trim(),
    bindUrl: String(source.bindUrl || '').trim(),
    qrUrl: String(source.qrUrl || '').trim(),
    gameAccount: String(source.gameAccount || '').trim(),
    expectedGameAccount: String(source.expectedGameAccount || '').trim(),
    bindMismatch: Boolean(source.bindMismatch),
    bound: Boolean(source.bound),
    boundAccount: String(source.boundAccount || '').trim(),
    gameChannel: String(source.gameChannel || '').trim(),
    submitStatus: String(source.submitStatus || '').trim(),
    consumeStatus: String(source.consumeStatus || 'pending').trim(),
    lastSyncedAt: source.lastSyncedAt || null,
    raw: source.raw && typeof source.raw === 'object' ? source.raw : null,
    mock:
      source.mock && typeof source.mock === 'object'
        ? {
            enabled: Boolean((source.mock as JsonObject).enabled),
            orderNo: String((source.mock as JsonObject).orderNo || '').trim(),
            createdAt: String((source.mock as JsonObject).createdAt || '').trim(),
          }
        : null,
  }
}

/**
 * client_order_no 优先使用平台订单号，方便商户侧直接按订单对账。
 * affiliate-dash 要求该字段唯一；同一订单拆成多笔 affiliate-dash 任务时追加稳定序号。
 */
export function buildAffiliateDashClientOrderNo(task: TaskRow, siblingTasks: TaskRow[] = []) {
  const platformOrderId = String(task.platform_order_id || '').trim()
  if (!platformOrderId) {
    return String(task.task_no || `OS-AD-${task.id}`).trim()
  }

  const affiliateDashTasks = siblingTasks
    .filter((candidate) => isAffiliateDashTask(candidate))
    .sort((left, right) => Number(left.id) - Number(right.id))

  if (affiliateDashTasks.length <= 1) {
    return platformOrderId
  }

  const position = affiliateDashTasks.findIndex((candidate) => candidate.id === task.id) + 1
  return `${platformOrderId}-${position > 0 ? position : task.id}`
}

async function preflightAffiliateDashWallet(sku: string) {
  try {
    const wallet = await getAffiliateDashWallet()
    if (wallet.availableBalance <= 0) {
      throw createHttpError('affiliate-dash 钱包余额不足，请先充值', {
        statusCode: 409,
        errorCode: 'affiliate_dash_wallet_not_enough',
        context: {
          sku,
          availableBalance: wallet.availableBalance,
          currency: wallet.currency,
        },
      })
    }
  } catch (error) {
    if ((error as { errorCode?: string })?.errorCode === 'affiliate_dash_wallet_not_enough') {
      throw error
    }
    logIntegration(
      '[affiliate-dash]',
      '余额预检失败（忽略，继续下单）',
      {
        sku,
        error: error instanceof Error ? error.message : String(error),
      },
      { level: 'warn' },
    )
  }
}

function buildAffiliateDashOrderData(task: TaskRow, context: Record<string, unknown>): JsonObject {
  const identity = getClaimIdentityFromContext(context)
  const data: JsonObject = {}

  const platformOrderId = String(task.platform_order_id || '').trim()
  if (platformOrderId) {
    data['91单号'] = platformOrderId
  }
  if (identity.expectedUid) {
    data.game_account = identity.expectedUid
  }

  return data
}

function mergeAffiliateDashOrder(
  flow: AffiliateDashFlow,
  order: AffiliateDashOrder,
  patch: {
    clientOrderNo?: string
    syncedAt: string
  },
): AffiliateDashFlow {
  return {
    ...flow,
    sku: order.sku || flow.sku,
    productName: order.productName || flow.productName,
    orderNo: order.orderNo || flow.orderNo,
    clientOrderNo: patch.clientOrderNo || flow.clientOrderNo,
    orderStatus: order.orderStatus || flow.orderStatus,
    canShip: order.canShip,
    cannotShipReason: order.cannotShipReason || flow.cannotShipReason,
    providerOrderNo: order.providerOrderNo || flow.providerOrderNo,
    failureReason: order.failureReason || flow.failureReason,
    amount: order.amount || flow.amount,
    currency: order.currency || flow.currency,
    lastSyncedAt: patch.syncedAt,
    raw: order.raw || flow.raw,
  }
}

/** 供阶段 4 领取页使用：读取 flow（context_json #>> '{affiliateDash,...}'）。 */
export function getAffiliateDashConfigSnapshot() {
  const config = getAffiliateDashConfig()
  return {
    enabled: config.enabled,
    baseUrl: config.baseUrl,
  }
}
