///|
pub struct CommunicationFilter {
  thread_id : String
  actor_id : String
  kind_id : String
  include_resolved_reviews : Bool
} derive(Debug, Eq)

///|
pub struct CommunicationBudget {
  max_visible_count : Int
  max_review_request_count : Int
  max_unresolved_review_count : Int
  max_artifact_ref_count : Int
} derive(Debug, Eq)

///|
pub struct CommunicationPlan {
  total_count : Int
  filtered_count : Int
  visible_count : Int
  hidden_count : Int
  visible_items : Array[Communication]
  review_request_count : Int
  unresolved_review_count : Int
  handoff_count : Int
  broadcast_count : Int
  tool_result_count : Int
  recovery_notice_count : Int
  artifact_ref_count : Int
  running_count : Int
  failed_count : Int
  diagnostics : Array[String]
  summary : String
} derive(Debug, Eq)

///|
pub fn communication_filter(
  thread_id? : String = "",
  actor_id? : String = "",
  kind_id? : String = "",
  include_resolved_reviews? : Bool = true,
) -> CommunicationFilter {
  { thread_id, actor_id, kind_id, include_resolved_reviews }
}

///|
pub fn all_communication_filter() -> CommunicationFilter {
  communication_filter()
}

///|
pub fn communication_budget(
  max_visible_count? : Int = 80,
  max_review_request_count? : Int = 32,
  max_unresolved_review_count? : Int = 16,
  max_artifact_ref_count? : Int = 32,
) -> CommunicationBudget {
  {
    max_visible_count,
    max_review_request_count,
    max_unresolved_review_count,
    max_artifact_ref_count,
  }
}

///|
pub fn default_communication_budget() -> CommunicationBudget {
  communication_budget()
}

///|
pub fn filter_communications(
  items : Array[Communication],
  filter : CommunicationFilter,
) -> Array[Communication] {
  let output : Array[Communication] = []
  for item in items {
    if communication_matches_filter(item, filter) {
      output.push(item)
    }
  }
  output
}

///|
pub fn plan_communications(items : Array[Communication]) -> CommunicationPlan {
  plan_filtered_communications(
    items,
    all_communication_filter(),
    budget=default_communication_budget(),
  )
}

///|
pub fn plan_communications_with_budget(
  items : Array[Communication],
  budget : CommunicationBudget,
) -> CommunicationPlan {
  plan_filtered_communications(items, all_communication_filter(), budget~)
}

///|
pub fn plan_filtered_communications(
  items : Array[Communication],
  filter : CommunicationFilter,
  budget? : CommunicationBudget = default_communication_budget(),
) -> CommunicationPlan {
  let filtered = filter_communications(items, filter)
  let visible_count = clamp_visible_count(
    filtered.length(),
    budget.max_visible_count,
  )
  let visible_items : Array[Communication] = []
  for i in 0..