///|
/// Forced pseudo-class states for interactive state simulation.
/// Used to evaluate CSS rules as if :hover, :focus, :active were active
/// on a target element.

///|
pub(all) struct ForcedPseudoStates {
  hover : Bool
  focus : Bool
  active : Bool
  focus_visible : Bool
  focus_within : Bool
} derive(Eq, Debug)

///|
pub impl Show for ForcedPseudoStates with fn output(self, logger) {
  logger.write_string("{hover: ")
  logger.write_string(self.hover.to_string())
  logger.write_string(", focus: ")
  logger.write_string(self.focus.to_string())
  logger.write_string(", active: ")
  logger.write_string(self.active.to_string())
  logger.write_string(", focus_visible: ")
  logger.write_string(self.focus_visible.to_string())
  logger.write_string(", focus_within: ")
  logger.write_string(self.focus_within.to_string())
  logger.write_string("}")
}

///|
pub fn ForcedPseudoStates::none() -> ForcedPseudoStates {
  {
    hover: false,
    focus: false,
    active: false,
    focus_visible: false,
    focus_within: false,
  }
}

///|
pub fn ForcedPseudoStates::is_empty(self : ForcedPseudoStates) -> Bool {
  !self.hover &&
  !self.focus &&
  !self.active &&
  !self.focus_visible &&
  !self.focus_within
}

///|
/// Check if an element matches a pseudo-class with forced states applied.
pub fn matches_pseudo_class_with_forced_states(
  element : Element,
  pc : PseudoClass,
  forced : ForcedPseudoStates,
) -> Bool {
  match pc {
    Hover => forced.hover
    Active => forced.active
    Focus => forced.focus
    FocusVisible => forced.focus_visible
    FocusWithin => forced.focus_within
    _ => matches_pseudo_class(element, pc)
  }
}

///|
/// Check if an element matches a simple selector with forced pseudo-class states.
fn matches_simple_with_forced_states(
  element : Element,
  selector : SimpleSelector,
  forced : ForcedPseudoStates,
) -> Bool {
  match selector {
    PseudoClass(pc) =>
      matches_pseudo_class_with_forced_states(element, pc, forced)
    _ => matches_simple(element, selector)
  }
}

///|
/// Check if an element matches a compound selector with forced states.
fn matches_compound_with_forced_states(
  element : Element,
  selector : CompoundSelector,
  forced : ForcedPseudoStates,
) -> Bool {
  match selector.type_selector {
    Some(type_sel) =>
      if !matches_simple_with_forced_states(element, type_sel, forced) {
        return false
      }
    None => ()
  }
  for sub in selector.subclasses {
    if !matches_simple_with_forced_states(element, sub, forced) {
      return false
    }
  }
  true
}

///|
/// Check if an element matches a complex selector with forced states.
/// Forced states only apply to the subject element (the head/rightmost selector).
pub fn matches_complex_with_forced_states(
  element : Element,
  selector : ComplexSelector,
  forced : ForcedPseudoStates,
) -> Bool {
  // The forced states apply to the subject (head) element only
  if !matches_compound_with_forced_states(element, selector.head, forced) {
    return false
  }
  if selector.tail.is_empty() {
    return true
  }
  // For ancestor/sibling selectors, use normal (non-forced) matching
  let mut current_element = element
  for step in selector.tail {
    match step.combinator {
      Descendant => {
        let mut found = false
        let mut ancestor = current_element.parent
        while true {
          match ancestor {
            None => break
            Some(anc) => {
              if matches_compound(anc, step.selector) {
                current_element = anc
                found = true
                break
              }
              ancestor = anc.parent
            }
          }
        }
        if !found {
          return false
        }
      }
      Child =>
        match current_element.parent {
          None => return false
          Some(parent) => {
            if !matches_compound(parent, step.selector) {
              return false
            }
            current_element = parent
          }
        }
      NextSibling =>
        match current_element.prev_sibling {
          None => return false
          Some(sibling) => {
            if !matches_compound(sibling, step.selector) {
              return false
            }
            current_element = sibling
          }
        }
      SubsequentSibling => {
        let mut found = false
        let mut sibling = current_element.prev_sibling
        while true {
          match sibling {
            None => break
            Some(sib) => {
              if matches_compound(sib, step.selector) {
                current_element = sib
                found = true
                break
              }
              sibling = sib.prev_sibling
            }
          }
        }
        if !found {
          return false
        }
      }
    }
  }
  true
}