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

///|
pub struct Group {
  value : Int
}

///|
pub fn Group::Group(bits : Int) -> Group {
  { value: bits }
}

///|
pub fn Group::bits(self : Group) -> Int {
  self.value
}

///|
pub fn Group::equals(self : Group, other : Group) -> Bool {
  self.value == other.value
}

///|
pub fn Group::none() -> Group {
  Group(0)
}

///|
pub fn Group::all() -> Group {
  Group(-1)
}

///|
pub fn Group::group_1() -> Group {
  Group(1 << 0)
}

///|
pub fn Group::group_2() -> Group {
  Group(1 << 1)
}

///|
pub fn Group::group_3() -> Group {
  Group(1 << 2)
}

///|
pub fn Group::group_4() -> Group {
  Group(1 << 3)
}

///|
pub fn Group::group_5() -> Group {
  Group(1 << 4)
}

///|
pub fn Group::group_6() -> Group {
  Group(1 << 5)
}

///|
pub fn Group::group_7() -> Group {
  Group(1 << 6)
}

///|
pub fn Group::group_8() -> Group {
  Group(1 << 7)
}

///|
pub fn Group::group_9() -> Group {
  Group(1 << 8)
}

///|
pub fn Group::group_10() -> Group {
  Group(1 << 9)
}

///|
pub fn Group::group_11() -> Group {
  Group(1 << 10)
}

///|
pub fn Group::group_12() -> Group {
  Group(1 << 11)
}

///|
pub fn Group::group_13() -> Group {
  Group(1 << 12)
}

///|
pub fn Group::group_14() -> Group {
  Group(1 << 13)
}

///|
pub fn Group::group_15() -> Group {
  Group(1 << 14)
}

///|
pub fn Group::group_16() -> Group {
  Group(1 << 15)
}

///|
pub fn Group::group_17() -> Group {
  Group(1 << 16)
}

///|
pub fn Group::group_18() -> Group {
  Group(1 << 17)
}

///|
pub fn Group::group_19() -> Group {
  Group(1 << 18)
}

///|
pub fn Group::group_20() -> Group {
  Group(1 << 19)
}

///|
pub fn Group::group_21() -> Group {
  Group(1 << 20)
}

///|
pub fn Group::group_22() -> Group {
  Group(1 << 21)
}

///|
pub fn Group::group_23() -> Group {
  Group(1 << 22)
}

///|
pub fn Group::group_24() -> Group {
  Group(1 << 23)
}

///|
pub fn Group::group_25() -> Group {
  Group(1 << 24)
}

///|
pub fn Group::group_26() -> Group {
  Group(1 << 25)
}

///|
pub fn Group::group_27() -> Group {
  Group(1 << 26)
}

///|
pub fn Group::group_28() -> Group {
  Group(1 << 27)
}

///|
pub fn Group::group_29() -> Group {
  Group(1 << 28)
}

///|
pub fn Group::group_30() -> Group {
  Group(1 << 29)
}

///|
pub fn Group::group_31() -> Group {
  Group(1 << 30)
}

///|
pub fn Group::group_32() -> Group {
  Group(1 << 31)
}

///|
pub fn Group::or(self : Group, other : Group) -> Group {
  Group(self.value | other.value)
}

///|
pub fn Group::intersection(self : Group, other : Group) -> Group {
  Group(self.value & other.value)
}

///|
pub struct InteractionGroups {
  mut memberships : Group
  mut filter : Group
  test_mode : InteractionTestMode
}

///|
pub fn InteractionGroups::InteractionGroups(
  memberships : Group,
  filter : Group,
  test_mode : InteractionTestMode,
) -> InteractionGroups {
  { memberships, filter, test_mode }
}

///|
pub fn InteractionGroups::all() -> InteractionGroups {
  InteractionGroups(Group::all(), Group::all(), And)
}

///|
pub fn InteractionGroups::none() -> InteractionGroups {
  InteractionGroups(Group::none(), Group::none(), And)
}

///|
pub fn InteractionGroups::with_memberships(
  self : InteractionGroups,
  memberships : Group,
) -> InteractionGroups {
  self.memberships = memberships
  self
}

///|
pub fn InteractionGroups::with_filter(
  self : InteractionGroups,
  filter : Group,
) -> InteractionGroups {
  self.filter = filter
  self
}

///|
pub fn InteractionGroups::test_and(
  self : InteractionGroups,
  other : InteractionGroups,
) -> Bool {
  (self.memberships.bits() & other.filter.bits()) != 0 &&
  (other.memberships.bits() & self.filter.bits()) != 0
}

///|
pub fn InteractionGroups::test_or(
  self : InteractionGroups,
  other : InteractionGroups,
) -> Bool {
  (self.memberships.bits() & other.filter.bits()) != 0 ||
  (other.memberships.bits() & self.filter.bits()) != 0
}

///|
pub fn InteractionGroups::test_groups(
  self : InteractionGroups,
  other : InteractionGroups,
) -> Bool {
  match self.test_mode {
    And => self.test_and(other)
    Or =>
      match other.test_mode {
        And => self.test_and(other)
        Or => self.test_or(other)
      }
  }
}

///|
pub fn InteractionGroups::passes(
  self : InteractionGroups,
  other : InteractionGroups,
) -> Bool {
  self.test_groups(other)
}

///|
pub fn InteractionGroups::memberships(self : InteractionGroups) -> Group {
  self.memberships
}

///|
pub fn InteractionGroups::filter(self : InteractionGroups) -> Group {
  self.filter
}

///|
pub fn InteractionGroups::test_mode(
  self : InteractionGroups,
) -> InteractionTestMode {
  self.test_mode
}

///|
pub fn InteractionGroups::default() -> InteractionGroups {
  InteractionGroups(Group::group_1(), Group::all(), And)
}