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))
}

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)

  console.log('\n--- Messages after create ---')
  console.log('Sales messages:', sales.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch messages:', dispatch.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Construction messages:', construction.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))

  // 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)

  console.log('\n--- Messages after approve ---')
  console.log('Sales messages:', sales.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch messages:', dispatch.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))

  // Step 3: Dispatch dispatches task to construction team 90
  console.log('\n--- Step 3: Dispatch dispatches task to team 90 ---')
  // Need a vehicle. Let's query vehicles first.
  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)

  console.log('\n--- Messages after dispatch ---')
  console.log('Sales messages:', sales.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch messages:', dispatch.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Construction messages:', construction.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))

  // Step 4: Construction confirms task
  console.log('\n--- Step 4: Construction confirms task ---')
  const confirmRes = await request('POST', '/sop/execute-step', {
    taskId,
    stepCode: 'confirm',
    action: 'confirm',
    operatorId: ROLES.construction.userId,
    operatorName: ROLES.construction.name,
  }, TOKENS.construction)
  console.log('Confirm task response:', confirmRes.code, confirmRes.msg)

  await wait(2000)

  console.log('\n--- Messages after confirm ---')
  console.log('Sales messages:', sales.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch messages:', dispatch.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))

  // Step 5: Construction completes task (SOP finish step)
  console.log('\n--- Step 5: Construction completes task ---')
  const completeRes = await request('POST', '/sop/execute-step', {
    taskId,
    stepCode: 'finish',
    action: 'finish',
    operatorId: ROLES.construction.userId,
    operatorName: ROLES.construction.name,
  }, TOKENS.construction)
  console.log('Complete task response:', completeRes.code, completeRes.msg)

  await wait(2000)

  console.log('\n--- Messages after complete ---')
  console.log('Sales messages:', sales.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))
  console.log('Dispatch messages:', dispatch.messages.filter(m => m.type !== 'connected' && m.type !== 'pong').map(m => ({ type: m.type, title: m.title, content: m.content })))

  // Check persisted messages
  console.log('\n--- Persisted messages for sales ---')
  const salesMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.sales)
  console.log('Sales persisted messages:', 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('\n--- Persisted messages for dispatch ---')
  const dispatchMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.dispatch)
  console.log('Dispatch persisted messages:', 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 })))

  console.log('\n--- Persisted messages for construction ---')
  const constructionMsgRes = await request('GET', '/message/list?pageNum=1&pageSize=50', null, TOKENS.construction)
  console.log('Construction persisted messages:', constructionMsgRes.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()
}

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