///| Utility functions for converting and validating modifiers

///|
/// Convert NodeArray[ModifierKind] to ClassMemberModifiers with validation
fn parse_class_member_modifiers(
  modifiers : Array[ModifierKind]?,
  span : Span,
) -> ClassMemberModifiers raise ParseError {
  match modifiers {
    None => ClassMemberModifiers::new()
    Some(mods) => {
      let mut accessibility : AccessibilityModifier? = None
      let mut is_static = false
      let mut is_abstract = false
      let mut is_readonly = false
      let mut is_override = false
      let mut is_accessor = false
      let mut is_async = false
      for modifier in mods {
        match modifier {
          ModifierKind::Public => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Public)
          }
          ModifierKind::Private => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Private)
          }
          ModifierKind::Protected => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Protected)
          }
          ModifierKind::Static => {
            if is_static {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Static),
              )
            }
            is_static = true
          }
          ModifierKind::Abstract => {
            if is_abstract {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Abstract),
              )
            }
            is_abstract = true
          }
          ModifierKind::Readonly => {
            if is_readonly {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Readonly),
              )
            }
            is_readonly = true
          }
          ModifierKind::Override => {
            if is_override {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Override),
              )
            }
            is_override = true
          }
          ModifierKind::Accessor => {
            if is_accessor {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Accessor),
              )
            }
            is_accessor = true
          }
          ModifierKind::Async => {
            if is_async {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Async),
              )
            }
            is_async = true
          }
          _ =>
            raise ParseError(
              span~,
              kind=ParseErrorKind::InvalidModifierForClassMember(modifier),
            )
        }
      }
      // Validate invalid combinations
      if is_abstract && is_static {
        raise ParseError(
          span~,
          kind=ParseErrorKind::AbstractAndStaticCannotCombine,
        )
      }
      if is_abstract && accessibility == Some(AccessibilityModifier::Private) {
        raise ParseError(
          span~,
          kind=ParseErrorKind::AbstractMembersCannotBePrivate,
        )
      }
      if is_abstract && is_async {
        raise ParseError(
          span~,
          kind=ParseErrorKind::AbstractAndAsyncCannotCombine,
        )
      }
      if is_accessor && is_abstract {
        raise ParseError(
          span~,
          kind=ParseErrorKind::AccessorAndAbstractCannotCombine,
        )
      }
      {
        accessibility,
        is_static,
        is_abstract,
        is_readonly,
        is_override,
        is_accessor,
        is_async,
      }
    }
  }
}

///|
/// Convert NodeArray[ModifierKind] to ParameterModifiers with validation
fn parse_parameter_modifiers(
  modifiers : NodeArray[ModifierKind]?,
  span : Span,
) -> ParameterModifiers raise ParseError {
  match modifiers {
    None => ParameterModifiers::new()
    Some(mods) => {
      let mut accessibility : AccessibilityModifier? = None
      let mut is_readonly = false
      for modifier in mods.elements.iter() {
        match modifier {
          ModifierKind::Public => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Public)
          }
          ModifierKind::Private => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Private)
          }
          ModifierKind::Protected => {
            if accessibility is Some(_) {
              raise ParseError(
                span~,
                kind=ParseErrorKind::MultipleAccessibilityModifiers,
              )
            }
            accessibility = Some(AccessibilityModifier::Protected)
          }
          ModifierKind::Readonly => {
            if is_readonly {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Readonly),
              )
            }
            is_readonly = true
          }
          _ =>
            raise ParseError(
              span~,
              kind=ParseErrorKind::InvalidModifierForParameter(modifier),
            )
        }
      }
      { accessibility, is_readonly }
    }
  }
}

///|
/// Convert NodeArray[ModifierKind] to TopLevelModifiers with validation
fn parse_top_level_modifiers(
  modifiers : NodeArray[ModifierKind]?,
  allow_abstract : Bool,
  allow_const : Bool,
  span : Span,
) -> TopLevelModifiers raise ParseError {
  match modifiers {
    None => TopLevelModifiers::new()
    Some(mods) => {
      let mut is_export = false
      let mut is_default = false
      let mut is_declare = false
      for modifier in mods.elements.iter() {
        match modifier {
          ModifierKind::Export => {
            if is_export {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Export),
              )
            }
            is_export = true
          }
          ModifierKind::Default => {
            if is_default {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Default),
              )
            }
            is_default = true
          }
          ModifierKind::Declare => {
            if is_declare {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Declare),
              )
            }
            is_declare = true
          }
          ModifierKind::Abstract =>
            if !allow_abstract {
              raise ParseError(
                span~,
                kind=ParseErrorKind::AbstractOnlyValidOnClasses,
              )
            }
          ModifierKind::Const =>
            if !allow_const {
              raise ParseError(
                span~,
                kind=ParseErrorKind::ConstOnlyValidOnEnums,
              )
            }
          ModifierKind::Async => () // Handled separately by FunctionDecl
          _ =>
            raise ParseError(
              span~,
              kind=ParseErrorKind::InvalidModifierForTopLevel(modifier),
            )
        }
      }
      { is_export, is_default, is_declare }
    }
  }
}

///|
/// Convert NodeArray[ModifierKind] to TypeParameterModifiers with validation
fn parse_type_parameter_modifiers(
  modifiers : NodeArray[ModifierKind]?,
  span : Span,
) -> TypeParameterModifiers raise ParseError {
  match modifiers {
    None => TypeParameterModifiers::new()
    Some(mods) => {
      let mut has_in = false
      let mut has_out = false
      let mut is_const = false
      for modifier in mods.elements.iter() {
        match modifier {
          ModifierKind::In => {
            if has_in {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::In),
              )
            }
            has_in = true
          }
          ModifierKind::Out => {
            if has_out {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Out),
              )
            }
            has_out = true
          }
          ModifierKind::Const => {
            if is_const {
              raise ParseError(
                span~,
                kind=ParseErrorKind::DuplicateModifier(ModifierKind::Const),
              )
            }
            is_const = true
          }
          _ =>
            raise ParseError(
              span~,
              kind=ParseErrorKind::InvalidModifierForTypeParameter(modifier),
            )
        }
      }
      // Set variance based on flags
      let variance = if has_in && has_out {
        Some(VarianceModifier::InOut)
      } else if has_in {
        Some(VarianceModifier::In)
      } else if has_out {
        Some(VarianceModifier::Out)
      } else {
        None
      }
      { variance, is_const }
    }
  }
}