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

import { useApprovalTaskQueue } from '../src/composables/useApprovalTaskQueue.js'

function queueItem(id, overrides = {}) {
  return {
    task: {
      id,
      claimId: `claim-${id}`,
      status: 'pending',
      version: 1,
      canAct: true,
      availableActions: ['approve'],
      batchEligible: true,
      claimStatusSnapshot: 'submitted',
      claimStageSnapshot: '直属领导审批',
      ...overrides
    },
    claim: { id: `claim-${id}`, claim_no: `BX-${id}` }
  }
}

function listResult(items, page = 1) {
  return {
    items,
    total: items.length,
    page,
    pageSize: 20,
    totalPages: items.length ? 1 : 0,
    generatedAt: '2026-07-16T10:00:00Z'
  }
}

function deferred() {
  let resolve
  let reject
  const promise = new Promise((resolvePromise, rejectPromise) => {
    resolve = resolvePromise
    reject = rejectPromise
  })
  return { promise, reject, resolve }
}

test('列表请求代次阻止慢请求覆盖新页结果', async () => {
  const requests = []
  const queue = useApprovalTaskQueue({
    services: {
      fetchApprovalTasks(params) {
        const request = deferred()
        requests.push({ params, request })
        return request.promise
      }
    }
  })

  const firstLoad = queue.loadQueue()
  await queue.setPage(2, { reload: false })
  const secondLoad = queue.loadQueue()
  requests[1].request.resolve(listResult([queueItem('task-new')], 2))
  await secondLoad
  requests[0].request.resolve(listResult([queueItem('task-stale')], 1))
  const staleResult = await firstLoad

  assert.equal(requests[0].params.page, 1)
  assert.equal(requests[1].params.page, 2)
  assert.equal(staleResult.ignored, true)
  assert.equal(queue.items.value[0].task.id, 'task-new')
  assert.equal(queue.page.value, 2)
})

test('筛选变化清空选择并回到第一页', async () => {
  const queue = useApprovalTaskQueue({
    services: {
      async fetchApprovalTasks() {
        return listResult([queueItem('task-001')])
      }
    }
  })
  await queue.loadQueue()
  queue.toggleTask(queue.items.value[0], true)
  await queue.setPage(3, { reload: false })
  assert.deepEqual(queue.selectedTaskIds.value, ['task-001'])

  await queue.setFilters({ riskLevel: 'high' }, { reload: false })
  assert.equal(queue.page.value, 1)
  assert.equal(queue.filters.value.riskLevel, 'high')
  assert.deepEqual(queue.selectedTaskIds.value, [])
})

test('批量部分成功保留失败选择并使用逐项任务快照', async () => {
  const batchCalls = []
  let listCallCount = 0
  const rows = [queueItem('task-001'), queueItem('task-002')]
  const queue = useApprovalTaskQueue({
    services: {
      async fetchApprovalTasks() {
        listCallCount += 1
        return listResult(rows)
      },
      async batchApproveApprovalTasks(payload) {
        batchCalls.push(payload)
        return {
          batchRequestId: payload.batchRequestId,
          status: 'partial',
          succeededCount: 1,
          replayedCount: 0,
          conflictCount: 0,
          blockedCount: 1,
          forbiddenCount: 0,
          failedCount: 0,
          items: [
            { taskId: 'task-001', status: 'succeeded' },
            { taskId: 'task-002', status: 'blocked', message: '存在开放高风险' }
          ]
        }
      }
    }
  })

  await queue.loadQueue()
  queue.toggleCurrentPage(true)
  const result = await queue.batchApprove({ opinion: '批量核对完成' })

  assert.equal(listCallCount, 2)
  assert.equal(batchCalls.length, 1)
  assert.equal(batchCalls[0].items[0].task.id, 'task-001')
  assert.equal(batchCalls[0].items[0].opinion, '批量核对完成')
  assert.equal(result.status, 'partial')
  assert.deepEqual(queue.selectedTaskIds.value, ['task-002'])
  assert.equal(queue.lastBatchResult.value.items[1].status, 'blocked')
  assert.equal(queue.pendingBatchRequestId.value, '')
})

test('单项刷新采用服务端最新权限并移除失效选择', async () => {
  const queue = useApprovalTaskQueue({
    services: {
      async fetchApprovalTasks() {
        return listResult([queueItem('task-001')])
      },
      async fetchApprovalTaskDetail() {
        return queueItem('task-001', {
          version: 2,
          canAct: false,
          availableActions: [],
          batchEligible: false,
          readOnlyReason: '任务已转交给其他审批人'
        })
      }
    }
  })

  await queue.loadQueue()
  queue.toggleTask(queue.items.value[0], true)
  await queue.refreshTask('task-001')

  assert.equal(queue.items.value[0].task.version, 2)
  assert.equal(queue.items.value[0].task.readOnlyReason, '任务已转交给其他审批人')
  assert.deepEqual(queue.selectedTaskIds.value, [])
})

test('批量选择在前端基础层限制为服务端允许的 20 项', async () => {
  const rows = Array.from({ length: 21 }, (_, index) => queueItem(`task-${index + 1}`))
  const queue = useApprovalTaskQueue({
    services: {
      async fetchApprovalTasks() {
        return listResult(rows)
      }
    }
  })

  await queue.loadQueue()
  queue.toggleCurrentPage(true)

  assert.equal(queue.selectedTaskIds.value.length, 20)
  assert.match(queue.errorMessage.value, /最多选择 20 项/)
})

test('批量失败按相同负载复用幂等键，编辑意见后生成新键', async () => {
  const requestIds = []
  const queue = useApprovalTaskQueue({
    services: {
      async fetchApprovalTasks() {
        return listResult([queueItem('task-retry')])
      },
      async batchApproveApprovalTasks(payload) {
        requestIds.push(payload.batchRequestId)
        throw new Error('模拟网络中断')
      }
    }
  })

  await queue.loadQueue()
  queue.toggleCurrentPage(true)
  await assert.rejects(queue.batchApprove({ opinion: '核对通过' }), /模拟网络中断/)
  await assert.rejects(queue.batchApprove({ opinion: '核对通过' }), /模拟网络中断/)
  await assert.rejects(queue.batchApprove({ opinion: '补充核对后通过' }), /模拟网络中断/)

  assert.equal(requestIds[1], requestIds[0])
  assert.notEqual(requestIds[2], requestIds[0])
})
