import test from 'node:test'
import assert from 'node:assert/strict'

import { redeemClaimTaskWithInventoryFallbackWithDeps } from './claim-session-service.js'

test('redeemClaimTaskWithInventoryFallbackWithDeps invalidates missing CDKEY and retries with replacement inventory', async () => {
  const events = []
  const invalidated = []
  const reserveCalls = []
  const reloadCalls = []

  const context = {
    task: {
      id: 42,
      browser_session_id: 'txbs-test',
    },
    orderItem: {
      sku_code: 'df-cdk',
    },
  }
  const initialInventoryItem = {
    id: 1,
    display_value: 'DJQFf7HgONCL4XD4EH',
    credential_type: 'tencent_code',
    inventory_group_code: 'A组',
  }
  const replacementInventoryItem = {
    id: 2,
    display_value: 'ABCD1234EFGH5678',
    credential_type: 'tencent_code',
    inventory_group_code: 'A组',
  }

  let redeemCount = 0
  const result = await redeemClaimTaskWithInventoryFallbackWithDeps(
    context,
    initialInventoryItem,
    {
      reloadTencentBrowserSession: async (sessionId) => {
        reloadCalls.push(sessionId)
        return { sessionId, status: 'ready_to_redeem' }
      },
      redeemTencentBrowserSession: async (sessionId, payload) => {
        redeemCount += 1
        if (redeemCount === 1) {
          assert.equal(sessionId, 'txbs-test')
          assert.equal(payload.code, 'DJQFf7HgONCL4XD4EH')
          return {
            redeem: {
              final: {
                redeem: {
                  iRet: -183,
                  sMsg: '该CDKEY不存在，请您确认后输入!',
                },
              },
            },
          }
        }

        assert.equal(payload.code, 'ABCD1234EFGH5678')
        return {
          redeem: {
            final: {
              redeem: {
                iRet: 0,
                sMsg: '领取成功',
              },
            },
          },
        }
      },
      invalidateReservedInventoryItem: async (inventoryItemId, reason, updatedAt) => {
        invalidated.push({ inventoryItemId, reason, updatedAt })
        return { id: inventoryItemId, status: 'invalid', invalid_reason: reason, updated_at: updatedAt }
      },
      reserveInventoryForTask: async (payload) => {
        reserveCalls.push(payload)
        return replacementInventoryItem
      },
      createTaskEvent: async (taskId, eventType, payload, createdAt) => {
        events.push({ taskId, eventType, payload, createdAt })
      },
      nowIso: (() => {
        const values = [
          '2026-04-14T12:03:34.000Z',
          '2026-04-14T12:03:35.000Z',
        ]
        let index = 0
        return () => values[index++] || values[values.length - 1]
      })(),
    },
  )

  assert.equal(result.inventoryItem.id, 2)
  assert.equal(result.classification.outcome, 'success')
  assert.equal(result.attempts.length, 2)
  assert.deepEqual(
    result.attempts.map((attempt) => ({
      attempt: attempt.attempt,
      inventoryItemId: attempt.inventoryItemId,
      outcome: attempt.outcome,
      resultCode: attempt.resultCode,
    })),
    [
      {
        attempt: 1,
        inventoryItemId: 1,
        outcome: 'code_invalid',
        resultCode: '-183',
      },
      {
        attempt: 2,
        inventoryItemId: 2,
        outcome: 'success',
        resultCode: '0',
      },
    ],
  )
  assert.deepEqual(invalidated, [
    {
      inventoryItemId: 1,
      reason: '该CDKEY不存在，请您确认后输入!',
      updatedAt: '2026-04-14T12:03:34.000Z',
    },
  ])
  assert.deepEqual(reserveCalls, [
    {
      skuCode: 'df-cdk',
      taskId: 42,
      credentialType: 'tencent_code',
      roleKey: 'primary_code',
      inventoryGroupCodes: ['A组'],
    },
  ])
  assert.deepEqual(reloadCalls, ['txbs-test'])
  assert.deepEqual(
    events.map((event) => ({
      eventType: event.eventType,
      taskId: event.taskId,
      createdAt: event.createdAt,
      payload: event.payload,
    })),
    [
      {
        eventType: 'claim_redeem_code_invalid',
        taskId: 42,
        createdAt: '2026-04-14T12:03:34.000Z',
        payload: {
          inventoryItemId: 1,
          codeMasked: 'DJQF****D4EH',
          resultCode: '-183',
          resultMessage: '该CDKEY不存在，请您确认后输入!',
        },
      },
      {
        eventType: 'claim_redeem_inventory_replaced',
        taskId: 42,
        createdAt: '2026-04-14T12:03:35.000Z',
        payload: {
          previousInventoryItemId: 1,
          previousCodeMasked: 'DJQF****D4EH',
          previousOutcome: 'code_invalid',
          nextInventoryItemId: 2,
          nextCodeMasked: 'ABCD****5678',
          credentialType: 'tencent_code',
          inventoryGroupCode: 'A组',
        },
      },
    ],
  )
})

test('redeemClaimTaskWithInventoryFallbackWithDeps waits for inventory when used code has no replacement', async () => {
  const events = []
  const consumed = []
  const reserveCalls = []

  const context = {
    task: {
      id: 57,
      browser_session_id: 'txbs-used',
    },
    orderItem: {
      sku_code: 'df-cdk-used',
    },
  }
  const initialInventoryItem = {
    id: 7,
    display_value: 'USED1234CODE5678',
    credential_type: 'tencent_code',
    inventory_group_code: 'B组',
  }

  let thrown = null
  try {
    await redeemClaimTaskWithInventoryFallbackWithDeps(
      context,
      initialInventoryItem,
      {
        redeemTencentBrowserSession: async () => ({
          redeem: {
            final: {
              redeem: {
                popup: {
                  text: '兑换结果',
                  detail: '兑换码已使用。',
                },
              },
            },
          },
        }),
        markInventoryItemConsumed: async (inventoryItemId, reason, updatedAt) => {
          consumed.push({ inventoryItemId, reason, updatedAt })
          return { id: inventoryItemId, status: 'consumed', invalid_reason: reason, updated_at: updatedAt }
        },
        reserveInventoryForTask: async (payload) => {
          reserveCalls.push(payload)
          return null
        },
        createTaskEvent: async (taskId, eventType, payload, createdAt) => {
          events.push({ taskId, eventType, payload, createdAt })
        },
        nowIso: () => '2026-04-14T12:05:00.000Z',
      },
    )
  } catch (error) {
    thrown = error
  }

  assert.ok(thrown)
  assert.equal(thrown.errorCode, 'claim_inventory_replacement_exhausted')
  assert.equal(thrown.redeemTaskState.taskStatus, 'waiting_inventory')
  assert.equal(thrown.redeemTaskState.inventoryStatus, 'pending')
  assert.equal(thrown.redeemTaskState.deliveryStatus, 'pending')
  assert.equal(thrown.redeemTaskState.attempts.length, 1)
  assert.deepEqual(consumed, [
    {
      inventoryItemId: 7,
      reason: '兑换码已使用。',
      updatedAt: '2026-04-14T12:05:00.000Z',
    },
  ])
  assert.deepEqual(reserveCalls, [
    {
      skuCode: 'df-cdk-used',
      taskId: 57,
      credentialType: 'tencent_code',
      roleKey: 'primary_code',
      inventoryGroupCodes: ['B组'],
    },
  ])
  assert.deepEqual(
    events.map((event) => ({
      taskId: event.taskId,
      eventType: event.eventType,
      payload: event.payload,
      createdAt: event.createdAt,
    })),
    [
      {
        taskId: 57,
        eventType: 'claim_redeem_code_used',
        payload: {
          inventoryItemId: 7,
          codeMasked: 'USED****5678',
          resultCode: '',
          resultMessage: '兑换码已使用。',
        },
        createdAt: '2026-04-14T12:05:00.000Z',
      },
    ],
  )
})
