#include "Runtime/Weapon/CWeapon.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CScriptWater.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace metaforce {

CWeapon::CWeapon(TUniqueId uid, TAreaId aid, bool active, TUniqueId owner, EWeaponType type, std::string_view name,
                 const zeus::CTransform& xf, const CMaterialFilter& filter, const CMaterialList& mList,
                 const CDamageInfo& dInfo, EProjectileAttrib attribs, CModelData&& mData)
: CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList,
         CActorParameters::None().HotInThermal(true), kInvalidUniqueId)
, xe8_projectileAttribs(attribs)
, xec_ownerId(owner)
, xf0_weaponType(type)
, xf8_filter(filter)
, x110_origDamageInfo(dInfo)
, x12c_curDamageInfo(dInfo) {}

void CWeapon::Accept(metaforce::IVisitor& visitor) { visitor.Visit(this); }

void CWeapon::Think(float dt, CStateManager& mgr) {
  x148_curTime += dt;
  if ((xe8_projectileAttribs & EProjectileAttrib::DamageFalloff) == EProjectileAttrib::DamageFalloff) {
    float damMul = std::max(0.f, 1.f - x148_curTime * x14c_damageFalloffSpeed);
    x12c_curDamageInfo.SetDamage(x110_origDamageInfo.GetDamage() * damMul);
    x12c_curDamageInfo.SetRadius(x110_origDamageInfo.GetRadius() * damMul);
    x12c_curDamageInfo.SetKnockBackPower(x110_origDamageInfo.GetKnockBackPower() * damMul);
    x12c_curDamageInfo.SetWeaponMode(x110_origDamageInfo.GetWeaponMode());
    x12c_curDamageInfo.SetNoImmunity(false);
  } else {
    x12c_curDamageInfo = x110_origDamageInfo;
  }
  CEntity::Think(dt, mgr);
}

void CWeapon::Render(CStateManager&) {
  // Empty
}

EWeaponCollisionResponseTypes CWeapon::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
                                                                const CWeaponMode&, EProjectileAttrib) const {
  return EWeaponCollisionResponseTypes::Projectile;
}

void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager& mgr) {
  bool doRipple = true;
  float mag = 0.f;
  switch (xf0_weaponType) {
  case EWeaponType::Power:
    mag = 0.1f;
    break;
  case EWeaponType::Ice:
    mag = 0.3f;
    break;
  case EWeaponType::Wave:
    mag = 0.1f;
    break;
  case EWeaponType::Plasma:
    break;
  case EWeaponType::Missile:
    mag = 0.5f;
    break;
  case EWeaponType::Phazon:
    mag = 0.1f;
    break;
  default:
    doRipple = false;
    break;
  }

  if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot) &&
      state != EFluidState::InFluid)
    mag += 0.5f;
  if (True(xe8_projectileAttribs & EProjectileAttrib::Charged))
    mag += 0.25f;
  if (mag > 1.f)
    mag = 1.f;

  if (doRipple) {
    zeus::CVector3f pos = GetTranslation();
    pos.z() = float(water.GetTriggerBoundsWR().max.z());
    if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot)) {
      if (!water.CanRippleAtPoint(pos))
        doRipple = false;
    } else if (state == EFluidState::InFluid) {
      doRipple = false;
    }

    if (doRipple) {
      water.GetFluidPlane().AddRipple(mag, x8_uid, pos, water, mgr);
      mgr.GetFluidPlaneManager()->CreateSplash(x8_uid, mgr, water, pos, mag,
                                               state == EFluidState::EnteredFluid || state == EFluidState::LeftFluid);
    }
  }
}

} // namespace metaforce
