// Copyright (c) 2021 PSForever
package game.objectcreatevehicle

import net.psforever.packet._
import net.psforever.packet.game.objectcreate._
import net.psforever.packet.game.ObjectCreateMessage
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
import org.specs2.mutable._
import scodec.bits._

class BattleframeRoboticsTest extends Specification {
  val string_aphelion_gunner = hex"17 80 02 00 00 AA 0B F0 15 EB 1C FE C3 30 90 40 00 00 E4 40 00 0F FF F0 00 00 F2 08 18 CC 13 C0 60 B2 00 00 00 10 11 94 2A 00 C0 64 00 00 1A 04 D8 0C 1E 40 00 00 02 02 32 85 60 18 0C 80 00 03 10 99 01 84 C8 00 00 00 40 46 10 CE 03 01 90 00 00"
  val string_aphelion_flight = hex"17 f6010000 a98 8901 5eb1c fec33 0904 00 00 0e4 40000ffff0000002040866102030390000000808ca1cc0603200000d0140060b20000001011943c00c06400000"

  "Battle Frame Robotics" should {
    "decode (aphelion)" in {
      PacketCoding.decodePacket(string_aphelion_gunner).require match {
        case ObjectCreateMessage(len, cls, guid, parent, data) =>
          len mustEqual 640L
          cls mustEqual ObjectClass.aphelion_gunner
          guid mustEqual PlanetSideGUID(447)
          parent.isDefined mustEqual false
          data match {
            case BattleFrameRoboticsData(pos, vdata, health, shields, unk1, unk2, no_mount_points, drive_state, proper_anim, unk3, show_shield, unk4, Some(inv)) =>
              pos.coord mustEqual Vector3(6498.7344f, 1927.9844f, 16.140625f)
              pos.orient mustEqual Vector3.z(50.625f)
              pos.vel.isEmpty mustEqual true

              vdata match {
                case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, vguid) =>
                  faction mustEqual PlanetSideEmpire.VS
                  bops mustEqual false
                  alternate mustEqual false
                  v1 mustEqual true
                  v2.isEmpty mustEqual true
                  v3 mustEqual false
                  v4.isEmpty mustEqual true
                  v5.isEmpty mustEqual true
                  vguid mustEqual PlanetSideGUID(0)
                case _ =>
                  ko
              }

              health mustEqual 255
              shields mustEqual 255
              unk1 mustEqual 0
              unk2 mustEqual false
              no_mount_points mustEqual false
              drive_state mustEqual 60
              proper_anim mustEqual true
              unk3 mustEqual 0
              show_shield mustEqual false
              unk4.isEmpty mustEqual true

              inv match {
                case InventoryData(list) =>
                  list.head.objectClass mustEqual ObjectClass.aphelion_ppa_left
                  list.head.guid mustEqual PlanetSideGUID(335)
                  list.head.parentSlot mustEqual 2
                  list.head.obj match {
                    case WeaponData(wdata, fire_mode, ammo, unk) =>
                      wdata match {
                        case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, wguid) =>
                          faction mustEqual PlanetSideEmpire.NEUTRAL
                          bops mustEqual false
                          alternate mustEqual false
                          v1 mustEqual true
                          v2.isEmpty mustEqual true
                          v3 mustEqual false
                          v4.contains(false) mustEqual true
                          v5.isEmpty mustEqual true
                          wguid mustEqual PlanetSideGUID(0)
                        case _ =>
                          ko
                      }
                      fire_mode mustEqual 0
                      ammo.head.objectClass mustEqual ObjectClass.aphelion_ppa_ammo
                      ammo.head.guid mustEqual PlanetSideGUID(340)
                      ammo.head.parentSlot mustEqual 0
                      unk mustEqual false
                    case _ =>
                      ko
                  }

                  list(1).objectClass mustEqual ObjectClass.aphelion_ppa_right
                  list(1).guid mustEqual PlanetSideGUID(411)
                  list(1).parentSlot mustEqual 3
                  list(1).obj match {
                    case WeaponData(wdata, fire_mode, ammo, unk) =>
                      wdata match {
                        case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, wguid) =>
                          faction mustEqual PlanetSideEmpire.NEUTRAL
                          bops mustEqual false
                          alternate mustEqual false
                          v1 mustEqual true
                          v2.isEmpty mustEqual true
                          v3 mustEqual false
                          v4.contains(false) mustEqual true
                          v5.isEmpty mustEqual true
                          wguid mustEqual PlanetSideGUID(0)
                        case _ =>
                          ko
                      }
                      fire_mode mustEqual 0
                      ammo.head.objectClass mustEqual ObjectClass.aphelion_ppa_ammo
                      ammo.head.guid mustEqual PlanetSideGUID(342)
                      ammo.head.parentSlot mustEqual 0
                      unk mustEqual false
                    case _ =>
                      ko
                  }

                  list(2).objectClass mustEqual ObjectClass.aphelion_plasma_rocket_pod
                  list(2).guid mustEqual PlanetSideGUID(409)
                  list(2).parentSlot mustEqual 4
                  list(2).obj match {
                    case WeaponData(wdata, fire_mode, ammo, unk) =>
                      wdata match {
                        case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, wguid) =>
                          faction mustEqual PlanetSideEmpire.NEUTRAL
                          bops mustEqual false
                          alternate mustEqual false
                          v1 mustEqual true
                          v2.isEmpty mustEqual true
                          v3 mustEqual false
                          v4.contains(false) mustEqual true
                          v5.isEmpty mustEqual true
                          wguid mustEqual PlanetSideGUID(0)
                        case _ =>
                          ko
                      }
                      fire_mode mustEqual 0
                      ammo.head.objectClass mustEqual ObjectClass.aphelion_plasma_rocket_ammo
                      ammo.head.guid mustEqual PlanetSideGUID(359)
                      ammo.head.parentSlot mustEqual 0
                      unk mustEqual false
                    case _ =>
                      ko
                  }
                case _ =>
                  ko
              }
            case _ =>
              ko
          }
        case _ =>
          ko
      }
    }

    "decode (eclipse)" in {
      PacketCoding.decodePacket(string_aphelion_flight).require match {
        case ObjectCreateMessage(len, cls, guid, parent, data) =>
          len mustEqual 502L
          cls mustEqual ObjectClass.aphelion_flight
          guid mustEqual PlanetSideGUID(393)
          parent.isDefined mustEqual false
          data match {
            case BattleFrameRoboticsData(pos, vdata, health, shields, unk1, unk2, no_mount_points, drive_state, proper_anim, unk3, show_shield, unk4, Some(inv)) =>
              pos.coord mustEqual Vector3(6498.7344f, 1927.9844f, 16.140625f)
              pos.orient mustEqual Vector3.z(50.625f)
              pos.vel.isEmpty mustEqual true

              vdata match {
                case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, vguid) =>
                  faction mustEqual PlanetSideEmpire.VS
                  bops mustEqual false
                  alternate mustEqual false
                  v1 mustEqual true
                  v2.isEmpty mustEqual true
                  v3 mustEqual false
                  v4.isEmpty mustEqual true
                  v5.isEmpty mustEqual true
                  vguid mustEqual PlanetSideGUID(0)
                case _ =>
                  ko
              }

              health mustEqual 255
              shields mustEqual 255
              unk1 mustEqual 0
              unk2 mustEqual false
              no_mount_points mustEqual false
              drive_state mustEqual 0
              proper_anim mustEqual true
              unk3 mustEqual 0
              show_shield mustEqual false
              unk4.contains(false) mustEqual true

              inv match {
                case InventoryData(list) =>
                  list.head.objectClass mustEqual ObjectClass.aphelion_ppa_left
                  list.head.guid mustEqual PlanetSideGUID(385)
                  list.head.parentSlot mustEqual 1
                  list.head.obj match {
                    case WeaponData(wdata, fire_mode, ammo, unk) =>
                      wdata match {
                        case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, wguid) =>
                          faction mustEqual PlanetSideEmpire.NEUTRAL
                          bops mustEqual false
                          alternate mustEqual false
                          v1 mustEqual true
                          v2.isEmpty mustEqual true
                          v3 mustEqual false
                          v4.contains(false) mustEqual true
                          v5.isEmpty mustEqual true
                          wguid mustEqual PlanetSideGUID(0)
                        case _ =>
                          ko
                      }
                      fire_mode mustEqual 0
                      ammo.head.objectClass mustEqual ObjectClass.aphelion_ppa_ammo
                      ammo.head.guid mustEqual PlanetSideGUID(371)
                      ammo.head.parentSlot mustEqual 0
                      unk mustEqual false
                    case _ =>
                      ko
                  }

                  list(1).objectClass mustEqual ObjectClass.aphelion_ppa_right
                  list(1).guid mustEqual PlanetSideGUID(336)
                  list(1).parentSlot mustEqual 2
                  list(1).obj match {
                    case WeaponData(wdata, fire_mode, ammo, unk) =>
                      wdata match {
                        case CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, wguid) =>
                          faction mustEqual PlanetSideEmpire.NEUTRAL
                          bops mustEqual false
                          alternate mustEqual false
                          v1 mustEqual true
                          v2.isEmpty mustEqual true
                          v3 mustEqual false
                          v4.contains(false) mustEqual true
                          v5.isEmpty mustEqual true
                          wguid mustEqual PlanetSideGUID(0)
                        case _ =>
                          ko
                      }
                      fire_mode mustEqual 0
                      ammo.head.objectClass mustEqual ObjectClass.aphelion_ppa_ammo
                      ammo.head.guid mustEqual PlanetSideGUID(376)
                      ammo.head.parentSlot mustEqual 0
                      unk mustEqual false
                    case _ =>
                      ko
                  }
                case _ =>
                  ko
              }
            case _ =>
              ko
          }
        case _ =>
          ko
      }
    }

    "encode (aphelion)" in {
      val obj = BattleFrameRoboticsData(
        PlacementData(6498.7344f, 1927.9844f, 16.140625f, 0, 0, 50.625f),
        CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)),
        255,
        255,
        0,
        false,
        false,
        60,
        true,
        0,
        false,
        None,
        Some(InventoryData(List(
          InventoryItemData(ObjectClass.aphelion_ppa_left, PlanetSideGUID(335), 2,
            WeaponData(
              CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)),
              0,
              List(
                InternalSlot(ObjectClass.aphelion_ppa_ammo, PlanetSideGUID(340), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))
              )
            )
          ),
          InventoryItemData(ObjectClass.aphelion_ppa_right, PlanetSideGUID(411), 3,
            WeaponData(
              CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)),
              0,
              List(
                InternalSlot(ObjectClass.aphelion_ppa_ammo, PlanetSideGUID(342), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))
              )
            )
          ),
          InventoryItemData(ObjectClass.aphelion_plasma_rocket_pod, PlanetSideGUID(409), 4,
            WeaponData(
              CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)),
              0,
              List(
                InternalSlot(ObjectClass.aphelion_plasma_rocket_ammo, PlanetSideGUID(359), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))
              )
            )
          )
        )))
      )
      val msg = ObjectCreateMessage(ObjectClass.aphelion_gunner, PlanetSideGUID(447), obj)
      val pkt = PacketCoding.encodePacket(msg).require.toByteVector

      pkt mustEqual string_aphelion_gunner
    }

    "encode (eclipse)" in {
      val obj = BattleFrameRoboticsData(
        PlacementData(6498.7344f, 1927.9844f, 16.140625f, 0, 0, 50.625f),
        CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, None, None, PlanetSideGUID(0)),
        255,
        255,
        0,
        false,
        false,
        0,
        true,
        0,
        false,
        Some(false),
        Some(InventoryData(List(
          InventoryItemData(ObjectClass.aphelion_ppa_left, PlanetSideGUID(385), 1,
            WeaponData(
              CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)),
              0,
              List(
                InternalSlot(ObjectClass.aphelion_ppa_ammo, PlanetSideGUID(371), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))
              )
            )
          ),
          InventoryItemData(ObjectClass.aphelion_ppa_right, PlanetSideGUID(336), 2,
            WeaponData(
              CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)),
              0,
              List(
                InternalSlot(ObjectClass.aphelion_ppa_ammo, PlanetSideGUID(376), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, Some(false), None, PlanetSideGUID(0)))
              )
            )
          )
        )))
      )
      val msg = ObjectCreateMessage(ObjectClass.aphelion_flight, PlanetSideGUID(393), obj)
      val pkt = PacketCoding.encodePacket(msg).require.toByteVector

      pkt mustEqual string_aphelion_flight
    }
  }
}
