///|
/// CSS Cascade - Declaration and Origin types
/// Based on CSS Cascading and Inheritance Level 4

///|
/// Origin of a CSS declaration
/// Ordered from lowest to highest precedence for normal declarations
pub(all) enum Origin {
  /// User-agent stylesheet (browser defaults)
  UserAgent
  /// User stylesheet (user preferences)
  User
  /// Author stylesheet (page styles)
  Author
}

///|
pub impl Show for Origin with fn output(self, logger) {
  match self {
    UserAgent => logger.write_string("UserAgent")
    User => logger.write_string("User")
    Author => logger.write_string("Author")
  }
}

///|
/// Importance of a declaration
pub(all) enum Importance {
  Normal
  Important
}

///|
pub impl Show for Importance with fn output(self, logger) {
  match self {
    Normal => logger.write_string("Normal")
    Important => logger.write_string("Important")
  }
}

///|
/// A CSS property value that can be a specific value or a keyword
pub(all) enum PropertyValue {
  /// A specific CSS value (parsed)
  Value(String)
  /// inherit keyword
  Inherit
  /// initial keyword
  Initial
  /// unset keyword
  Unset
  /// revert keyword
  Revert
  /// revert-layer keyword
  RevertLayer
}

///|
/// Parse a declaration value, preserving CSS-wide keywords for computed-value
/// resolution instead of treating them as property-specific strings.
pub fn PropertyValue::from_css_text(value : String) -> PropertyValue {
  match value.trim().to_lower() {
    "inherit" => Inherit
    "initial" => Initial
    "unset" => Unset
    "revert" => Revert
    "revert-layer" => RevertLayer
    _ => Value(value)
  }
}

///|
pub impl Show for PropertyValue with fn output(self, logger) {
  match self {
    Value(v) => {
      logger.write_string("Value(")
      logger.write_string(v)
      logger.write_string(")")
    }
    Inherit => logger.write_string("inherit")
    Initial => logger.write_string("initial")
    Unset => logger.write_string("unset")
    Revert => logger.write_string("revert")
    RevertLayer => logger.write_string("revert-layer")
  }
}

///|
/// A CSS declaration with cascade metadata
pub(all) struct Declaration {
  /// Property name (e.g., "width", "display")
  property : String
  /// Property value
  value : PropertyValue
  /// Origin of this declaration
  origin : Origin
  /// Whether this declaration has !important
  importance : Importance
  /// Selector specificity (from the rule that contains this declaration)
  specificity : @selector.Specificity
  /// Source order (higher = later in source)
  source_order : Int
}

///|
pub impl Show for Declaration with fn output(self, logger) {
  logger.write_string(self.property)
  logger.write_string(": ")
  self.value.output(logger)
  match self.importance {
    Important => logger.write_string(" !important")
    Normal => ()
  }
}

///|
/// Create a new declaration with default values
pub fn Declaration::new(property : String, value : String) -> Declaration {
  {
    property,
    value: PropertyValue::from_css_text(value),
    origin: Author,
    importance: Normal,
    specificity: @selector.Specificity::zero(),
    source_order: 0,
  }
}

///|
/// Create a declaration with full metadata
pub fn Declaration::with_metadata(
  property : String,
  value : PropertyValue,
  origin : Origin,
  importance : Importance,
  specificity : @selector.Specificity,
  source_order : Int,
) -> Declaration {
  { property, value, origin, importance, specificity, source_order }
}

///|
/// Create a declaration from inline style (highest specificity)
pub fn Declaration::from_inline(
  property : String,
  value : String,
  importance : Importance,
) -> Declaration {
  {
    property,
    value: PropertyValue::from_css_text(value),
    origin: Author,
    importance,
    // Inline styles have specificity (1,0,0,0) but we represent as (1,0,0) with special handling
    specificity: { a: 1, b: 0, c: 0 },
    source_order: 0,
  }
}

///|
/// Cascade precedence level
/// Higher value = higher precedence
fn cascade_precedence(origin : Origin, importance : Importance) -> Int {
  match (origin, importance) {
    // Lowest to highest precedence for cascade
    // 1. Normal user-agent
    (UserAgent, Normal) => 1
    // 2. Normal user
    (User, Normal) => 2
    // 3. Normal author
    (Author, Normal) => 3
    // 4. !important author
    (Author, Important) => 4
    // 5. !important user
    (User, Important) => 5
    // 6. !important user-agent
    (UserAgent, Important) => 6
    // Note: Transitions (7) and Animations (5) are not handled here
  }
}

///|
/// Compare two declarations for cascade ordering
/// Returns positive if a wins, negative if b wins, 0 if equal
fn compare_declarations(a : Declaration, b : Declaration) -> Int {
  // 1. Compare cascade precedence (origin + importance)
  let prec_a = cascade_precedence(a.origin, a.importance)
  let prec_b = cascade_precedence(b.origin, b.importance)
  if prec_a != prec_b {
    return prec_a - prec_b
  }

  // 2. Compare specificity
  let spec_cmp = a.specificity.compare_to(b.specificity)
  if spec_cmp != 0 {
    return spec_cmp
  }

  // 3. Compare source order (later wins)
  a.source_order - b.source_order
}