import Core from './core.js'

export default class tribes1 extends Core {
  constructor () {
    super()
    this.encoding = 'latin1'
    this.requestByte = 0x62
    this.responseByte = 0x63
    this.challenge = 0x01
  }

  async run (state) {
    const query = Buffer.alloc(3)
    query.writeUInt8(this.requestByte, 0)
    query.writeUInt16LE(this.challenge, 1)
    const reader = await this.udpSend(query, (buffer) => {
      const reader = this.reader(buffer)
      const responseByte = reader.uint(1)
      if (responseByte !== this.responseByte) {
        this.logger.debug('Unexpected response byte')
        return
      }
      const challenge = reader.uint(2)
      if (challenge !== this.challenge) {
        this.logger.debug('Unexpected challenge')
        return
      }
      const requestByte = reader.uint(1)
      if (requestByte !== this.requestByte) {
        this.logger.debug('Unexpected request byte')
        return
      }
      return reader
    })

    state.raw.gametype = this.readString(reader)
    const isStarsiege2009 = state.raw.gametype === 'Starsiege'
    state.version = this.readString(reader)
    state.name = this.readString(reader)

    if (isStarsiege2009) {
      state.password = !!reader.uint(1)
      state.raw.dedicated = !!reader.uint(1)
      state.raw.dropInProgress = !!reader.uint(1)
      state.raw.gameInProgress = !!reader.uint(1)
      state.numplayers = reader.uint(4)
      state.maxplayers = reader.uint(4)
      state.raw.teamPlay = reader.uint(1)
      state.map = this.readString(reader)
      state.raw.cpuSpeed = reader.uint(2)
      state.raw.factoryVeh = reader.uint(1)
      state.raw.allowTecmix = reader.uint(1)
      state.raw.spawnLimit = reader.uint(4)
      state.raw.fragLimit = reader.uint(4)
      state.raw.timeLimit = reader.uint(4)
      state.raw.techLimit = reader.uint(4)
      state.raw.combatLimit = reader.uint(4)
      state.raw.massLimit = reader.uint(4)
      state.raw.playersSent = reader.uint(4)
      const teams = { 1: 'yellow', 2: 'blue', 4: 'red', 8: 'purple' }
      while (!reader.done()) {
        const player = {}
        player.name = this.readString(reader)
        const teamId = reader.uint(1)
        const team = teams[teamId]
        if (team) player.team = teams[teamId]
      }
      return
    }

    state.raw.dedicated = !!reader.uint(1)
    state.password = !!reader.uint(1)
    state.raw.playerCount = reader.uint(1)
    state.maxplayers = reader.uint(1)
    state.raw.cpuSpeed = reader.uint(2)
    state.raw.mod = this.readString(reader)
    state.raw.type = this.readString(reader)
    state.map = this.readString(reader)
    state.raw.motd = this.readString(reader)
    state.raw.teamCount = reader.uint(1)

    const teamFields = this.readFieldList(reader)
    const playerFields = this.readFieldList(reader)

    state.raw.teams = []
    for (let i = 0; i < state.raw.teamCount; i++) {
      const teamName = this.readString(reader)
      const teamValues = this.readValues(reader)

      const teamInfo = {}
      for (let i = 0; i < teamValues.length && i < teamFields.length; i++) {
        let key = teamFields[i]
        let value = teamValues[i]
        if (key === 'ultra_base') key = 'name'
        if (value === '%t') value = teamName
        if (['score', 'players'].includes(key)) value = parseInt(value)
        teamInfo[key] = value
      }
      state.raw.teams.push(teamInfo)
    }

    for (let i = 0; i < state.raw.playerCount; i++) {
      const ping = reader.uint(1) * 4
      const packetLoss = reader.uint(1)
      const teamNum = reader.uint(1)
      const name = this.readString(reader)
      const playerValues = this.readValues(reader)

      const playerInfo = {}
      for (let i = 0; i < playerValues.length && i < playerFields.length; i++) {
        const key = playerFields[i]
        let value = playerValues[i]
        if (value === '%p') value = ping
        if (value === '%l') value = packetLoss
        if (value === '%t') value = teamNum
        if (value === '%n') value = name
        if (['score', 'ping', 'pl', 'kills', 'lvl'].includes(key)) value = parseInt(value)
        if (key === 'team') {
          const teamId = parseInt(value)
          if (teamId >= 0 && teamId < state.raw.teams.length && state.raw.teams[teamId].name) {
            value = state.raw.teams[teamId].name
          } else {
            continue
          }
        }
        playerInfo[key] = value
      }
      state.players.push(playerInfo)
    }
  }

  readFieldList (reader) {
    const str = this.readString(reader)
    if (!str) return []
    return ('?' + str)
      .split('\t')
      .map((a) => a.substring(1).trim().toLowerCase())
      .map((a) => a === 'team name' ? 'name' : a)
      .map((a) => a === 'player name' ? 'name' : a)
  }

  readValues (reader) {
    const str = this.readString(reader)
    if (!str) return []
    return str
      .split('\t')
      .map((a) => a.trim())
  }

  readString (reader) {
    return reader.pascalString(1)
  }
}
