// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
const ACTIVE_EVENTS_COLLISION_EVENTS : Int = 1 << 0

///|
const ACTIVE_EVENTS_CONTACT_FORCE_EVENTS : Int = 1 << 1

///|
const ACTIVE_EVENTS_INTERSECTION_EVENTS : Int = 1 << 2

///|
pub struct ActiveEvents {
  mut bits : Int
}

///|
fn ActiveEvents::ActiveEvents(bits : Int) -> ActiveEvents {
  { bits, }
}

///|
fn active_events_all_bits() -> Int {
  ACTIVE_EVENTS_COLLISION_EVENTS |
  ACTIVE_EVENTS_CONTACT_FORCE_EVENTS |
  ACTIVE_EVENTS_INTERSECTION_EVENTS
}

///|
pub fn ActiveEvents::empty() -> ActiveEvents {
  ActiveEvents(0)
}

///|
pub fn ActiveEvents::collision_events() -> ActiveEvents {
  ActiveEvents(ACTIVE_EVENTS_COLLISION_EVENTS)
}

///|
pub fn ActiveEvents::contact_force_events() -> ActiveEvents {
  ActiveEvents(ACTIVE_EVENTS_CONTACT_FORCE_EVENTS)
}

///|
pub fn ActiveEvents::intersection_events() -> ActiveEvents {
  ActiveEvents(ACTIVE_EVENTS_INTERSECTION_EVENTS)
}

///|
pub fn ActiveEvents::contains(
  self : ActiveEvents,
  other : ActiveEvents,
) -> Bool {
  (self.bits & other.bits) == other.bits
}

///|
pub fn ActiveEvents::insert(
  self : ActiveEvents,
  other : ActiveEvents,
) -> ActiveEvents {
  self.bits = self.bits | other.bits
  self
}

///|
pub fn ActiveEvents::union(
  self : ActiveEvents,
  other : ActiveEvents,
) -> ActiveEvents {
  { bits: self.bits | other.bits }
}

///|
pub fn ActiveEvents::difference(
  self : ActiveEvents,
  other : ActiveEvents,
) -> ActiveEvents {
  { bits: self.bits & Int::lnot(other.bits) }
}

///|
pub fn ActiveEvents::symmetric_difference(
  self : ActiveEvents,
  other : ActiveEvents,
) -> ActiveEvents {
  { bits: self.bits ^ other.bits }
}

///|
pub fn ActiveEvents::toggle(
  self : ActiveEvents,
  other : ActiveEvents,
) -> ActiveEvents {
  self.symmetric_difference(other)
}

///|
pub fn ActiveEvents::complement(self : ActiveEvents) -> ActiveEvents {
  { bits: active_events_all_bits() & Int::lnot(self.bits) }
}

///|
pub fn ActiveEvents::is_all(self : ActiveEvents) -> Bool {
  (self.bits & active_events_all_bits()) == active_events_all_bits()
}

///|
pub fn ActiveEvents::from_bits(bits : Int) -> ActiveEvents? {
  if (bits & Int::lnot(active_events_all_bits())) == 0 {
    Some({ bits, })
  } else {
    None
  }
}

///|
pub fn ActiveEvents::from_bits_truncate(bits : Int) -> ActiveEvents {
  { bits: bits & active_events_all_bits() }
}

///|
pub fn ActiveEvents::from_bits_retain(bits : Int) -> ActiveEvents {
  { bits, }
}

///|
pub fn ActiveEvents::iter_names(self : ActiveEvents) -> Array[String] {
  let result : Array[String] = []
  if self.contains(ActiveEvents::collision_events()) {
    result.push("COLLISION_EVENTS")
  }
  if self.contains(ActiveEvents::contact_force_events()) {
    result.push("CONTACT_FORCE_EVENTS")
  }
  if self.contains(ActiveEvents::intersection_events()) {
    result.push("INTERSECTION_EVENTS")
  }
  result
}

///|
pub fn ActiveEvents::from_name(name : String) -> ActiveEvents? {
  if name == "COLLISION_EVENTS" {
    Some(ActiveEvents::collision_events())
  } else if name == "CONTACT_FORCE_EVENTS" {
    Some(ActiveEvents::contact_force_events())
  } else if name == "INTERSECTION_EVENTS" {
    Some(ActiveEvents::intersection_events())
  } else {
    None
  }
}

///|
const COLLISION_EVENT_FLAG_SENSOR : Int = 1 << 0

///|
const COLLISION_EVENT_FLAG_REMOVED : Int = 1 << 1

///|
pub struct CollisionEventFlags {
  mut bits : Int
}

///|
fn CollisionEventFlags::CollisionEventFlags(bits : Int) -> CollisionEventFlags {
  { bits, }
}

///|
pub fn CollisionEventFlags::empty() -> CollisionEventFlags {
  CollisionEventFlags(0)
}

///|
pub fn CollisionEventFlags::sensor() -> CollisionEventFlags {
  CollisionEventFlags(COLLISION_EVENT_FLAG_SENSOR)
}

///|
pub fn CollisionEventFlags::removed() -> CollisionEventFlags {
  CollisionEventFlags(COLLISION_EVENT_FLAG_REMOVED)
}

///|
pub fn CollisionEventFlags::contains(
  self : CollisionEventFlags,
  other : CollisionEventFlags,
) -> Bool {
  (self.bits & other.bits) == other.bits
}

///|
pub fn CollisionEventFlags::insert(
  self : CollisionEventFlags,
  other : CollisionEventFlags,
) -> CollisionEventFlags {
  self.bits = self.bits | other.bits
  self
}

///|
pub fn CollisionEvent::started(self : CollisionEvent) -> Bool {
  match self {
    Started(_, _, _) => true
    _ => false
  }
}

///|
pub fn CollisionEvent::stopped(self : CollisionEvent) -> Bool {
  match self {
    Stopped(_, _, _) => true
    _ => false
  }
}

///|
pub fn CollisionEvent::collider1(self : CollisionEvent) -> ColliderHandle {
  match self {
    Started(h, _, _) => h
    Stopped(h, _, _) => h
  }
}

///|
pub fn CollisionEvent::collider2(self : CollisionEvent) -> ColliderHandle {
  match self {
    Started(_, h, _) => h
    Stopped(_, h, _) => h
  }
}

///|
pub fn CollisionEvent::sensor(self : CollisionEvent) -> Bool {
  match self {
    Started(_, _, flags) => flags.contains(CollisionEventFlags::sensor())
    Stopped(_, _, flags) => flags.contains(CollisionEventFlags::sensor())
  }
}

///|
pub fn CollisionEvent::removed(self : CollisionEvent) -> Bool {
  match self {
    Started(_, _, flags) => flags.contains(CollisionEventFlags::removed())
    Stopped(_, _, flags) => flags.contains(CollisionEventFlags::removed())
  }
}

///|
pub struct IntersectionEvent {
  collider1 : ColliderHandle
  collider2 : ColliderHandle
  intersecting : Bool
}

///|
pub fn IntersectionEvent::IntersectionEvent(
  collider1 : ColliderHandle,
  collider2 : ColliderHandle,
  intersecting : Bool,
) -> IntersectionEvent {
  { collider1, collider2, intersecting }
}

///|
pub fn IntersectionEvent::collider1(self : IntersectionEvent) -> ColliderHandle {
  self.collider1
}

///|
pub fn IntersectionEvent::collider2(self : IntersectionEvent) -> ColliderHandle {
  self.collider2
}

///|
pub fn IntersectionEvent::intersecting(self : IntersectionEvent) -> Bool {
  self.intersecting
}

///|
pub struct ContactForceEvent {
  collider1 : ColliderHandle
  collider2 : ColliderHandle
  total_force : @core.Vec2
  total_force_magnitude : @core.Real
  max_force_direction : @core.Vec2
  max_force_magnitude : @core.Real
}

///|
pub fn ContactForceEvent::ContactForceEvent(
  collider1 : ColliderHandle,
  collider2 : ColliderHandle,
  total_force : @core.Vec2,
  total_force_magnitude : @core.Real,
  max_force_direction : @core.Vec2,
  max_force_magnitude : @core.Real,
) -> ContactForceEvent {
  {
    collider1,
    collider2,
    total_force,
    total_force_magnitude,
    max_force_direction,
    max_force_magnitude,
  }
}

///|
pub fn ContactForceEvent::collider1(self : ContactForceEvent) -> ColliderHandle {
  self.collider1
}

///|
pub fn ContactForceEvent::collider2(self : ContactForceEvent) -> ColliderHandle {
  self.collider2
}

///|
pub fn ContactForceEvent::total_force(self : ContactForceEvent) -> @core.Vec2 {
  self.total_force
}

///|
pub fn ContactForceEvent::total_force_magnitude(
  self : ContactForceEvent,
) -> @core.Real {
  self.total_force_magnitude
}

///|
pub fn ContactForceEvent::max_force_direction(
  self : ContactForceEvent,
) -> @core.Vec2 {
  self.max_force_direction
}

///|
pub fn ContactForceEvent::max_force_magnitude(
  self : ContactForceEvent,
) -> @core.Real {
  self.max_force_magnitude
}