const WebSocket = require('ws')
const http = require('http')

const BASE_URL = 'http://localhost:8080/api'
const WS_URL = 'ws://localhost:8080/api/ws/notify'

const TOKENS = {
  sales: 'mock-token-mp-21',
  dispatch: 'mock-token-mp-13',
  construction: 'mock-token-mp-15',
}

const ROLES = {
  sales: { userId: 21, name: '徐云辉' },
  dispatch: { userId: 13, name: '张智城' },
  construction: { userId: 15, name: '测试实施1' },
}

function request(method, path, data, token) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname: 'localhost',
      port: 8080,
      path: '/api' + path,
      method,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
      },
    }
    const req = http.request(options, (res) => {
      let body = ''
      res.on('data', (chunk) => (body += chunk))
      res.on('end', () => {
        try {
          resolve(JSON.parse(body))
        } catch (e) {
          resolve(body)
        }
      })
    })
    req.on('error', reject)
    if (data) req.write(JSON.stringify(data))
    req.end()
  })
}

function connectWebSocket(role) {
  return new Promise((resolve, reject) => {
    const ws = new WebSocket(`${WS_URL}?token=${encodeURIComponent(TOKENS[role])}`)
    const messages = []
    ws.on('open', () => {
      console.log(`[${role}] WebSocket connected`)
      resolve({ ws, messages })
    })
    ws.on('message', (data) => {
      const msg = JSON.parse(data.toString())
      console.log(`[${role}] received raw:`, msg.type, msg.title || '', msg.content || '')
      messages.push(msg)
    })
    ws.on('error', (err) => {
      console.error(`[${role}] WebSocket error:`, err.message)
      reject(err)
    })
    ws.on('close', () => {
      console.log(`[${role}] WebSocket closed`)
    })
  })
}

function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

function filterMessages(messages, taskId, taskNo) {
  return messages.filter(m => m.type !== 'connected' && m.type !== 'pong')
    .filter(m => m.businessId == taskId || m.extraData == taskId || (m.content || '').includes(taskNo))
}

async function main() {
  console.log('Connecting WebSockets...')
  const sales = await connectWebSocket('sales')
  const dispatch = await connectWebSocket('dispatch')
  const construction = await connectWebSocket('construction')

  await wait(1000)

  // Step 1: Sales creates a task
  console.log('\n--- Step 1: Sales creates task ---')
  const taskNo = 'TK-TEST-' + Date.now()
  const createRes = await request('POST', '/task', {
    taskNo,
    projectId: 33,
    taskType: 'dredge',
    planDate: '2026-07-26',
    address: '测试地址',
    taskName: '测试任务-' + Date.now(),
  }, TOKENS.sales)
  console.log('Create task response:', createRes.code, createRes.msg)
  if (createRes.code !== 200) {
    console.error('Failed to create task:', createRes)
    process.exit(1)
  }
  const taskId = createRes.data

  await wait(2000)

  // Step 2: Dispatch approves task
  console.log('\n--- Step 2: Dispatch approves task ---')
  const approveRes = await request('POST', `/task/audit/${taskId}/approve`, {
    auditUserId: ROLES.dispatch.userId,
    auditUserName: ROLES.dispatch.name,
  }, TOKENS.dispatch)
  console.log('Approve task response:', approveRes.code, approveRes.msg)

  await wait(2000)

  // Step 3: Dispatch dispatches task to team 90
  console.log('\n--- Step 3: Dispatch dispatches task to team 90 ---')
  const vehicleRes = await request('GET', '/vehicle/list?pageNum=1&pageSize=1', null, TOKENS.dispatch)
  const vehicleId = vehicleRes.data?.rows?.[0]?.vehicleId || 1
  const dispatchRes = await request('POST', `/task/audit/${taskId}/dispatch`, {
    teamId: 90,
    vehicleId,
    auditUserId: ROLES.dispatch.userId,
    auditUserName: ROLES.dispatch.name,
  }, TOKENS.dispatch)
  console.log('Dispatch task response:', dispatchRes.code, dispatchRes.msg)

  await wait(2000)

  // Clear previous messages so we only capture reject/feedback notifications
  sales.messages.length = 0
  dispatch.messages.length = 0
  construction.messages.length = 0

  // Step 4: Construction rejects task
  console.log('\n--- Step 4: Construction rejects task ---')
  const taskRes = await request('GET', `/task/${taskId}`, null, TOKENS.construction)
  const task = taskRes.data
  const rejectReason = '测试拒绝原因-' + Date.now()
  const rejectUpdateRes = await request('PUT', '/task', {
    taskId,
    taskNo: task.taskNo,
    address: task.address,
    taskType: task.taskType,
    projectId: task.projectId,
    planDate: task.planDate,
    status: 'rejected',
    remark: rejectReason,
  }, TOKENS.construction)
  console.log('Reject update response:', rejectUpdateRes.code, rejectUpdateRes.msg)

  const rejectLogRes = await request('POST', `/task/${taskId}/log`, {
    operationType: 'reject',
    operation: '拒绝任务',
    remark: rejectReason,
    operatorId: ROLES.construction.userId,
    operatorName: ROLES.construction.name,
  }, TOKENS.construction)
  console.log('Reject log response:', rejectLogRes.code, rejectLogRes.msg)

  await wait(2000)

  // Step 5: Construction submits feedback
  console.log('\n--- Step 5: Construction submits feedback ---')
  const feedbackContent = '测试反馈内容-' + Date.now()
  const feedbackRes = await request('POST', `/task/${taskId}/log`, {
    operationType: 'feedback',
    operation: '反馈问题',
    remark: feedbackContent,
    operatorId: ROLES.construction.userId,
    operatorName: ROLES.construction.name,
  }, TOKENS.construction)
  console.log('Feedback response:', feedbackRes.code, feedbackRes.msg)

  await wait(2000)

  // Step 6: Check task logs
  console.log('\n--- Step 6: Task logs ---')
  const logsRes = await request('GET', `/task/${taskId}/logs`, null, TOKENS.construction)
  const logs = logsRes.data || []
  console.log('Recent logs for task:')
  logs.slice(-5).forEach(log => {
    console.log(`  [${log.operationType}] ${log.operation} | ${log.remark || '-'} | by ${log.operatorName}`)
  })
  const hasRejectLog = logs.some(l => l.operationType === 'reject')
  const hasFeedbackLog = logs.some(l => l.operationType === 'feedback')
  console.log('Has reject log:', hasRejectLog)
  console.log('Has feedback log:', hasFeedbackLog)

  // Step 7: Check WebSocket messages received after reject/feedback
  console.log('\n--- Step 7: WebSocket messages after reject/feedback ---')
  console.log('Sales:', filterMessages(sales.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch:', filterMessages(dispatch.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Construction:', filterMessages(construction.messages, taskId, taskNo).map(m => ({ type: m.type, title: m.title, content: m.content })))

  // Step 8: Check persisted messages
  console.log('\n--- Step 8: Persisted messages ---')
  const salesMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.sales)
  const dispatchMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.dispatch)

  console.log('Sales persisted messages related to task:',
    salesMsgRes.data?.rows?.filter(m => m.extraData == taskId || m.content?.includes(taskNo)).map(m => ({ type: m.messageType, title: m.title, content: m.content, isRead: m.isRead })))
  console.log('Dispatch persisted messages related to task:',
    dispatchMsgRes.data?.rows?.filter(m => m.extraData == taskId || m.content?.includes(taskNo)).map(m => ({ type: m.messageType, title: m.title, content: m.content, isRead: m.isRead })))

  sales.ws.close()
  dispatch.ws.close()
  construction.ws.close()

  console.log('\n=== Summary ===')
  console.log('Reject recorded in logs:', hasRejectLog)
  console.log('Feedback recorded in logs:', hasFeedbackLog)
  console.log('Sales WS notifications after reject/feedback:', filterMessages(sales.messages, taskId, taskNo).length)
  console.log('Dispatch WS notifications after reject/feedback:', filterMessages(dispatch.messages, taskId, taskNo).length)
  console.log('Sales persisted messages after reject/feedback:', (salesMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length)
  console.log('Dispatch persisted messages after reject/feedback:', (dispatchMsgRes.data?.rows || []).filter(m => m.extraData == taskId || m.content?.includes(taskNo)).length)
}

main().catch((err) => {
  console.error('Test failed:', err)
  process.exit(1)
})
