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

import {
  addSignApprovalTask,
  approveApprovalTask,
  batchApproveApprovalTasks,
  countersignApprovalTask,
  delegateApprovalTask,
  escalateApprovalTask,
  fetchApprovalTaskCandidates,
  fetchApprovalTaskDetail,
  fetchApprovalTasks,
  returnApprovalTask,
  revokeApprovalTaskDelegation,
  transferApprovalTask
} from '../src/services/approvalTasks.js'

function jsonResponse(payload) {
  return {
    ok: true,
    status: 200,
    async json() {
      return payload
    }
  }
}

function pendingTask(overrides = {}) {
  return {
    id: 'task-001',
    claim_id: 'claim-001',
    status: 'pending',
    version: 3,
    can_act: true,
    available_actions: ['approve', 'delegate'],
    batch_eligible: true,
    claim_status_snapshot: 'submitted',
    claim_stage_snapshot: '直属领导审批',
    priority_reasons_json: [{ code: 'sla_near_due', label: '即将超时', weight: 16 }],
    ...overrides
  }
}

test('审批任务列表发送服务端分页筛选参数并规范化任务', async () => {
  let capturedUrl = ''
  global.fetch = async (url) => {
    capturedUrl = String(url)
    return jsonResponse({
      items: [{ task: pendingTask(), claim: { id: 'claim-001', claim_no: 'BX-001' } }],
      total: 41,
      page: 2,
      page_size: 25,
      total_pages: 2,
      generated_at: '2026-07-16T10:00:00Z'
    })
  }

  const result = await fetchApprovalTasks({
    page: 2,
    pageSize: 25,
    status: 'pending',
    riskLevel: 'high',
    slaState: 'overdue',
    nodeKey: 'direct_manager',
    keyword: '张 三',
    batchEligible: true,
    sort: 'priority_desc'
  })

  const url = new URL(capturedUrl, 'http://local.test')
  assert.equal(url.pathname, '/api/v1/approval-tasks')
  assert.equal(url.searchParams.get('page'), '2')
  assert.equal(url.searchParams.get('page_size'), '25')
  assert.equal(url.searchParams.get('status'), 'pending')
  assert.equal(url.searchParams.get('risk_level'), 'high')
  assert.equal(url.searchParams.get('sla_state'), 'overdue')
  assert.equal(url.searchParams.get('node_key'), 'direct_manager')
  assert.equal(url.searchParams.get('keyword'), '张 三')
  assert.equal(url.searchParams.get('batch_eligible'), 'true')
  assert.equal(url.searchParams.get('sort'), 'priority_desc')
  assert.equal(result.total, 41)
  assert.equal(result.pageSize, 25)
  assert.equal(result.items[0].task.claimId, 'claim-001')
  assert.equal(result.items[0].task.priorityReasons[0].code, 'sla_near_due')
  assert.equal(result.items[0].claim.claim_no, 'BX-001')
})

test('审批任务详情和候选人使用任务作用域接口', async () => {
  const calls = []
  global.fetch = async (url) => {
    calls.push(String(url))
    if (String(url).includes('/candidates?')) {
      return jsonResponse({
        items: [{
          employee_id: 'employee-002',
          employee_no: 'E002',
          name: '李审批',
          email: 'li@example.com',
          qualified: false,
          reason: '不属于当前部门'
        }],
        total: 1
      })
    }
    return jsonResponse({ task: pendingTask(), claim: { id: 'claim-001' } })
  }

  const detail = await fetchApprovalTaskDetail('task/001')
  const candidates = await fetchApprovalTaskCandidates('task/001', {
    action: 'delegate',
    keyword: '李 审批',
    limit: 30
  })

  assert.equal(calls[0], '/api/v1/approval-tasks/task%2F001')
  const candidateUrl = new URL(calls[1], 'http://local.test')
  assert.equal(candidateUrl.pathname, '/api/v1/approval-tasks/task%2F001/candidates')
  assert.equal(candidateUrl.searchParams.get('action'), 'delegate')
  assert.equal(candidateUrl.searchParams.get('keyword'), '李 审批')
  assert.equal(candidateUrl.searchParams.get('limit'), '30')
  assert.equal(detail.task.id, 'task-001')
  assert.equal(candidates.items[0].qualified, false)
  assert.equal(candidates.items[0].reason, '不属于当前部门')
})

test('所有审批动作携带请求幂等键和任务版本', async () => {
  const calls = []
  global.fetch = async (url, options) => {
    calls.push({ url: String(url), body: JSON.parse(options.body) })
    return jsonResponse({ task: pendingTask({ version: 4 }), related_tasks: [], replayed: false })
  }
  const base = {
    requestId: 'request-action-001',
    expectedTaskVersion: 3,
    reason: '业务审批处理'
  }

  await delegateApprovalTask('task-001', {
    ...base,
    targetEmployeeId: 'employee-002',
    expiresAt: '2026-07-18T10:00:00Z'
  })
  await revokeApprovalTaskDelegation('task-001', base)
  await transferApprovalTask('task-001', { ...base, targetEmployeeId: 'employee-003' })
  await addSignApprovalTask('task-001', {
    ...base,
    participantEmployeeIds: ['employee-004', 'employee-005', 'employee-004']
  })
  await countersignApprovalTask('task-001', {
    ...base,
    participantEmployeeIds: ['employee-006', 'employee-007']
  })
  await escalateApprovalTask('task-001', base)
  await approveApprovalTask('task-001', { ...base, opinion: '同意通过' })
  await returnApprovalTask('task-001', {
    ...base,
    reasonCodes: ['missing_invoice', 'missing_invoice', 'amount_mismatch']
  })

  assert.deepEqual(calls.map((call) => call.url), [
    '/api/v1/approval-tasks/task-001/delegate',
    '/api/v1/approval-tasks/task-001/delegation/revoke',
    '/api/v1/approval-tasks/task-001/transfer',
    '/api/v1/approval-tasks/task-001/add-sign',
    '/api/v1/approval-tasks/task-001/countersign',
    '/api/v1/approval-tasks/task-001/escalate',
    '/api/v1/approval-tasks/task-001/approve',
    '/api/v1/approval-tasks/task-001/return'
  ])
  calls.forEach((call) => {
    assert.equal(call.body.request_id, 'request-action-001')
    assert.equal(call.body.expected_task_version, 3)
    assert.equal(call.body.reason, '业务审批处理')
  })
  assert.equal(calls[0].body.target_employee_id, 'employee-002')
  assert.equal(calls[0].body.expires_at, '2026-07-18T10:00:00Z')
  assert.deepEqual(calls[3].body.participant_employee_ids, ['employee-004', 'employee-005'])
  assert.equal(calls[6].body.opinion, '同意通过')
  assert.deepEqual(calls[7].body.reason_codes, ['missing_invoice', 'amount_mismatch'])
})

test('批量审批发送逐项快照并规范化部分成功结果', async () => {
  let capturedUrl = ''
  let capturedBody = null
  global.fetch = async (url, options) => {
    capturedUrl = String(url)
    capturedBody = JSON.parse(options.body)
    return jsonResponse({
      batch_request_id: 'batch-request-001',
      status: 'partial',
      succeeded_count: 1,
      blocked_count: 1,
      conflict_count: 1,
      items: [
        { task_id: 'task-001', claim_id: 'claim-001', status: 'succeeded', code: 'OK', message: '已通过' },
        { task_id: 'task-002', claim_id: 'claim-002', status: 'blocked', code: 'OPEN_RISK', message: '存在开放高风险' },
        { task_id: 'task-003', claim_id: 'claim-003', status: 'conflict', code: 'STALE_TASK', message: '任务已更新' }
      ]
    })
  }

  const result = await batchApproveApprovalTasks({
    batchRequestId: 'batch-request-001',
    items: [
      pendingTask({ id: 'task-001' }),
      pendingTask({ id: 'task-002', version: 5 }),
      {
        taskId: 'task-003',
        expectedTaskVersion: 2,
        expectedStatus: 'submitted',
        expectedApprovalStage: '财务审批',
        opinion: '票据已核对'
      }
    ]
  })

  assert.equal(capturedUrl, '/api/v1/approval-tasks/batch-approve')
  assert.equal(capturedBody.batch_request_id, 'batch-request-001')
  assert.deepEqual(capturedBody.items[0], {
    task_id: 'task-001',
    expected_task_version: 3,
    expected_status: 'submitted',
    expected_approval_stage: '直属领导审批'
  })
  assert.equal(capturedBody.items[1].expected_task_version, 5)
  assert.equal(capturedBody.items[2].opinion, '票据已核对')
  assert.equal(result.status, 'partial')
  assert.equal(result.succeededCount, 1)
  assert.equal(result.blockedCount, 1)
  assert.equal(result.conflictCount, 1)
  assert.equal(result.items[1].code, 'OPEN_RISK')
})
