import {
  getTencentBrowserSession,
  getTencentBrowserSessionScreenshotPath,
} from '../../session/session.js'
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { updateTask } from '../../../repositories/task-repo.js'
import {
  getInventoryItemById,
  markInventoryItemDelivered,
} from '../../../repositories/inventory-repo.js'
import { ensureAgisoXianyuAutoDeliveryForDeliveredTask } from '../../platforms/agiso/xianyu/auto-delivery-service.js'
import { syncKuaishouCloudRoleInfo } from '../kuaishou-cloud-sync-service.js'
import { notifyClaimRedeemNeedsAttention } from '../../notification/domain-notifications.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { getClaimContext, getClaimContextByTaskId } from './context.js'
import { loadTaskSession, syncTaskWithSession } from './runtime.js'
import { redeemClaimTaskWithInventoryFallback, resolveTencentRedeemResultCode } from './redeem.js'
import {
  assertPublicClaimActionAllowed,
  assertTaskCanProceed,
  buildClaimDetailPayload,
  maskCode,
  mergeTaskContext,
} from './shared.js'

export async function getClaimDetail(token, { includeQrImage = true } = {}) {
  const context = await getClaimContext(token)
  let { task, session } = await loadTaskSession(context.task, { includeQrImage })

  if (String(task.executor_key || '').trim() === 'kuaishou_ct_assisted') {
    task = await syncKuaishouCloudRoleInfo(task)
  }

  const syncedTask = session ? await syncTaskWithSession(task, session) : task

  return buildClaimDetailPayload({
    claimToken: context.claimToken,
    task: syncedTask,
    order: context.order,
    orderItem: context.orderItem,
    session,
  })
}

export async function getClaimDetailForAdminTask(taskId, { includeQrImage = true } = {}) {
  const context = await getClaimContextByTaskId(taskId)
  const { task, session } = await loadTaskSession(context.task, { includeQrImage })
  const syncedTask = session ? await syncTaskWithSession(task, session) : task

  return buildClaimDetailPayload({
    claimToken: context.claimToken,
    task: syncedTask,
    order: context.order,
    orderItem: context.orderItem,
    session,
  })
}

export async function getClaimSessionSummary(token) {
  return getClaimSessionSummaryByContextLoader(() => getClaimContext(token))
}

export async function getClaimSessionSummaryForAdminTask(taskId) {
  return getClaimSessionSummaryByContextLoader(() => getClaimContextByTaskId(taskId))
}

export async function confirmClaimRole(token) {
  const context = await getClaimContext(token)
  assertPublicClaimActionAllowed(context.task, 'confirm')

  return finalizeClaimRoleConfirmation(context)
}

export async function confirmClaimRoleForAdminTask(taskId) {
  const context = await getClaimContextByTaskId(taskId)

  return finalizeClaimRoleConfirmation(context)
}

export async function redeemClaimTask(token) {
  const context = await getClaimContext(token)
  assertTaskCanProceed(context.task)
  assertPublicClaimActionAllowed(context.task, 'redeem')

  return finalizeClaimTaskRedeem(context)
}

export async function redeemClaimTaskForAdminTask(taskId) {
  const context = await getClaimContextByTaskId(taskId)
  assertTaskCanProceed(context.task)

  return finalizeClaimTaskRedeem(context)
}

export async function getClaimScreenshotPath(token) {
  const context = await getClaimContext(token)

  if (context.task.screenshot_path) {
    return context.task.screenshot_path
  }

  if (!context.task.browser_session_id) {
    throw createHttpError('当前任务还没有兑换截图', {
      statusCode: 404,
      errorCode: 'claim_screenshot_not_ready',
    })
  }

  return getTencentBrowserSessionScreenshotPath(context.task.browser_session_id)
}

async function getClaimSessionSummaryByContextLoader(loadContext) {
  const context = await loadContext()
  const { task, session } = await loadTaskSession(context.task, {
    includeQrImage: false,
  })

  if (!session) {
    return buildClaimDetailPayload({
      claimToken: context.claimToken,
      task,
      order: context.order,
      orderItem: context.orderItem,
      session: null,
    })
  }

  const syncedTask = await syncTaskWithSession(task, session)

  return buildClaimDetailPayload({
    claimToken: context.claimToken,
    task: syncedTask,
    order: context.order,
    orderItem: context.orderItem,
    session,
  })
}

async function finalizeClaimRoleConfirmation(context) {
  if (!context.task.browser_session_id) {
    throw createHttpError('当前任务还没有创建浏览器会话', {
      statusCode: 409,
      errorCode: 'claim_session_not_created',
    })
  }

  const session = await getTencentBrowserSession(context.task.browser_session_id)
  const activityInfo = session.activityInfo || null

  if (!activityInfo?.role?.ready) {
    throw createHttpError('当前角色信息还没有准备好', {
      statusCode: 409,
      errorCode: 'claim_role_not_ready',
    })
  }

  const updatedTask = await updateTask(context.task.id, {
    task_status: 'role_confirmed',
    nickname: String(activityInfo.nickname || ''),
    role_id: String(activityInfo.role.roleId || ''),
    role_name: String(activityInfo.role.roleName || ''),
    area: String(activityInfo.role.area || ''),
    partition_name: String(activityInfo.role.partition || ''),
    user_action_status: 'role_confirmed',
    role_confirmed_at: nowIso(),
    updated_at: nowIso(),
    last_error: '',
  })

  return buildClaimDetailPayload({
    claimToken: context.claimToken,
    task: updatedTask,
    order: context.order,
    orderItem: context.orderItem,
    session,
  })
}

async function finalizeClaimTaskRedeem(context) {
  if (!context.task.browser_session_id) {
    throw createHttpError('当前任务还没有创建浏览器会话', {
      statusCode: 409,
      errorCode: 'claim_session_not_created',
    })
  }

  if (context.task.task_status !== 'role_confirmed' && context.task.task_status !== 'redeeming') {
    throw createHttpError('当前任务还未确认角色，不能开始兑换', {
      statusCode: 409,
      errorCode: 'claim_role_not_confirmed',
    })
  }

  const inventoryItem = context.task.primary_inventory_item_id
    ? await getInventoryItemById(context.task.primary_inventory_item_id)
    : null

  if (
    !inventoryItem ||
    String(inventoryItem.status || '').trim() !== 'reserved' ||
    !String(inventoryItem.display_value || '').trim()
  ) {
    throw createHttpError('当前任务没有可用的预占库存凭据', {
      statusCode: 409,
      errorCode: 'claim_inventory_not_reserved',
    })
  }

  await updateTask(context.task.id, {
    task_status: 'redeeming',
    delivery_status: 'processing',
    updated_at: nowIso(),
    last_error: '',
  })

  try {
    const redeemResult = await redeemClaimTaskWithInventoryFallback(context, inventoryItem)
    const { session, inventoryItem: deliveredInventoryItem, classification, attempts } = redeemResult
    const finalRedeem = session.redeem?.final?.redeem || null
    const finishedAt = nowIso()
    const updatedTask = await updateTask(context.task.id, {
      task_status: 'redeemed',
      inventory_status: 'consumed',
      delivery_status: 'delivered',
      result_code: resolveTencentRedeemResultCode(finalRedeem, classification),
      result_message: classification.message,
      screenshot_path: session.artifacts?.hasScreenshot ? await getTencentBrowserSessionScreenshotPath(session.sessionId) : '',
      artifacts_json: JSON.stringify(session.artifacts || {}),
      context_json: JSON.stringify(mergeTaskContext(context.task, {
        redeemResolution: {
          status: 'success',
          attempts,
          replacementCount: Math.max(0, attempts.length - 1),
          finishedAt,
        },
      })),
      redeemed_at: finishedAt,
      updated_at: finishedAt,
      last_error: '',
    })

    await markInventoryItemDelivered(deliveredInventoryItem.id, finishedAt)
    await createTaskEvent(context.task.id, 'claim_redeem_completed', {
      inventoryItemId: deliveredInventoryItem.id,
      codeMasked: maskCode(deliveredInventoryItem.display_value),
      replacementCount: Math.max(0, attempts.length - 1),
      resultCode: resolveTencentRedeemResultCode(finalRedeem, classification),
      resultMessage: classification.message,
    }, finishedAt)
    const autoDeliveryResult = await ensureAgisoXianyuAutoDeliveryForDeliveredTask({
      order: context.order,
      task: updatedTask,
      trigger: 'claim_redeemed',
    })

    return buildClaimDetailPayload({
      claimToken: context.claimToken,
      task: autoDeliveryResult.task || updatedTask,
      order: context.order,
      orderItem: context.orderItem,
      session,
    })
  } catch (error) {
    const now = nowIso()
    const nextRetryCount = Number(context.task.attempt_count || 0) + 1
    const failureState = (
      error && typeof error === 'object'
        ? /** @type {{ redeemTaskState?: { taskStatus: string, inventoryStatus: string, deliveryStatus: string, lastError: string, attempts: unknown[], classification: { retCode?: unknown } | null } }} */ (error).redeemTaskState
        : null
    ) || {
      taskStatus: 'retry_pending',
      inventoryStatus: inventoryItem ? 'reserved' : 'pending',
      deliveryStatus: 'pending',
      lastError: error instanceof Error ? error.message : String(error || ''),
      attempts: [],
      classification: null,
    }
    const failedTask = await updateTask(context.task.id, {
      task_status: failureState.taskStatus,
      inventory_status: failureState.inventoryStatus,
      delivery_status: failureState.deliveryStatus,
      result_code: failureState.classification?.retCode != null ? String(failureState.classification.retCode) : '',
      result_message: String(failureState.lastError || ''),
      attempt_count: nextRetryCount,
      last_error: String(failureState.lastError || ''),
      context_json: JSON.stringify(mergeTaskContext(context.task, {
        redeemResolution: {
          status: 'failed',
          taskStatus: failureState.taskStatus,
          attempts: failureState.attempts || [],
          replacementCount: Math.max(0, Number(failureState.attempts?.length || 1) - 1),
          finishedAt: now,
        },
      })),
      updated_at: now,
    })

    if (['retry_pending', 'waiting_inventory', 'manual_review'].includes(String(failureState.taskStatus || '').trim())) {
      await notifyClaimRedeemNeedsAttention({
        task: failedTask,
        order: context.order,
        status: failureState.taskStatus,
        errorMessage: failureState.lastError,
      })
    }

    throw Object.assign(error instanceof Error ? error : new Error(String(error || '兑换失败')), {
      task: failedTask,
    })
  }
}
