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 } from '../../../domain/task-status.js'
import type { TaskRow } from '../../../types/repository/rows.js'
import type { JsonObject } from './domain.js'
import type { DispatchStockResult } from './dispatch-types.js'

export async function markKuaishouCloudDispatchFailed(
  task: TaskRow,
  taskContext: JsonObject,
  flow: JsonObject,
  error: unknown,
  options: JsonObject = {},
) {
  const now = nowIso()
  const errorMessage = resolveErrorMessage(error)
  const errorCode = resolveErrorCode(error) || 'kuaishou_cloud_dispatch_failed'
  const failureContext = resolveDispatchFailureContext(error)
  const stockResult = isPlainObject(failureContext.stockResult)
    ? (failureContext.stockResult as Partial<DispatchStockResult>)
    : null
  const nextContext = {
    ...taskContext,
    kuaishouCloudFulfillment: {
      ...flow,
      dispatch: {
        ...(isPlainObject(flow.dispatch) ? flow.dispatch : {}),
        status: 'failed',
        failedAt: now,
        failedStage: String(failureContext.stage || '').trim(),
        errorCode,
        errorMessage,
        note: buildDispatchFailedMessage(errorMessage),
      },
      purchase: {
        ...(isPlainObject(flow.purchase) ? flow.purchase : {}),
        ...(stockResult
          ? {
              usedKnapsack: stockResult.usedKnapsack,
              purchaseTriggered: stockResult.purchaseTriggered,
              assetBefore: stockResult.assetBefore,
              assetAfter: stockResult.assetAfter,
              items: stockResult.items,
            }
          : {}),
      },
    },
  }

  await updateTask(task.id, {
    task_status: TASK_STATUS.MANUAL_REVIEW,
    user_action_status: 'not_required',
    last_error: errorMessage,
    result_code: errorCode,
    result_message: buildDispatchFailedMessage(errorMessage),
    context_json: JSON.stringify(nextContext),
    updated_at: now,
  })

  await createTaskEvent(
    task.id,
    'kuaishou_cloud_dispatch_failed',
    {
      source: String(options.source || 'system').trim() || 'system',
      actor: options.actor,
      errorCode,
      errorMessage,
      failureContext,
    },
    now,
  )
}

export function enrichCloudtentaclesDispatchError(error: unknown, context: JsonObject) {
  const currentError =
    error instanceof Error
      ? (error as Error & { context?: unknown })
      : (createHttpError(resolveErrorMessage(error), {
          statusCode: 500,
          errorCode: 'kuaishou_cloud_dispatch_failed',
        }) as Error & { context?: unknown })
  const currentContext = isPlainObject(currentError.context) ? currentError.context : {}
  currentError.context = {
    ...currentContext,
    dispatchFailure: {
      ...(isPlainObject((currentContext as JsonObject).dispatchFailure)
        ? ((currentContext as JsonObject).dispatchFailure as JsonObject)
        : {}),
      ...context,
    },
  }

  return currentError
}

export function resolveDispatchFailureContext(error: unknown): JsonObject {
  if (!error || typeof error !== 'object') {
    return {}
  }

  const context = (error as { context?: unknown }).context
  if (!isPlainObject(context)) {
    return {}
  }

  const dispatchFailure = context.dispatchFailure
  return isPlainObject(dispatchFailure) ? dispatchFailure : {}
}

export function resolveErrorCode(error: unknown) {
  if (!error || typeof error !== 'object') {
    return ''
  }

  return String((error as { errorCode?: unknown }).errorCode || '').trim()
}

export function resolveErrorMessage(error: unknown) {
  return error instanceof Error ? error.message : String(error || 'CloudTentacles 发货失败')
}

export function buildDispatchFailedMessage(message: unknown) {
  const reason = String(message || '').trim() || '未知错误'
  return `CloudTentacles 发货失败：${reason}`
}

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