///|
pub(all) enum ActorKind {
  Human
  Agent
  System
} derive(Debug, Eq)

///|
pub(all) enum RunStatus {
  Idle
  Running
  WaitingReview
  Done
  Failed
  Cancelled
} derive(Debug, Eq)

///|
pub(all) enum ReviewState {
  NotRequired
  Pending
  Approved
  Rejected
  CancelledReview
  FailedReview
} derive(Debug, Eq)

///|
pub struct Actor {
  id : String
  label : String
  kind : ActorKind
} derive(Debug, Eq)

///|
pub struct Message {
  id : String
  actor_id : String
  thread_id : String
  text : String
  artifact_ref : String
  status : RunStatus
} derive(Debug, Eq)

///|
pub struct ReviewAction {
  id : String
  label : String
  state : ReviewState
  approve_message : String
  reject_message : String
} derive(Debug, Eq)

///|
pub struct ToolResultCard {
  id : String
  tool_name : String
  title : String
  summary : String
  artifact_ref : String
  status : RunStatus
  open_message : String
  acknowledge_message : String
} derive(Debug, Eq)

///|
pub fn actor(id~ : String, label~ : String, kind? : ActorKind = Agent) -> Actor {
  { id, label, kind }
}

///|
pub fn message(
  id~ : String,
  actor_id~ : String,
  thread_id~ : String,
  text~ : String,
  artifact_ref? : String = "",
  status? : RunStatus = Done,
) -> Message {
  { id, actor_id, thread_id, text, artifact_ref, status }
}

///|
pub fn review_action(
  id~ : String,
  label~ : String,
  approve_message~ : String,
  reject_message~ : String,
  state? : ReviewState = Pending,
) -> ReviewAction {
  { id, label, state, approve_message, reject_message }
}

///|
pub fn tool_result_card(
  id~ : String,
  tool_name~ : String,
  title~ : String,
  summary~ : String,
  artifact_ref? : String = "",
  status? : RunStatus = Done,
  open_message? : String = "",
  acknowledge_message? : String = "",
) -> ToolResultCard {
  {
    id,
    tool_name,
    title,
    summary,
    artifact_ref,
    status,
    open_message,
    acknowledge_message,
  }
}

///|
pub fn review_action_enabled(action : ReviewAction) -> Bool {
  action.state is Pending
}

///|
pub fn message_row(item : Message) -> @core.Node {
  let attrs = [
    @core.class_name("bunnia-message \{run_status_class(item.status)}"),
    @core.data("message-id", item.id),
    @core.data("thread-id", item.thread_id),
    @core.data("actor-id", item.actor_id),
    @core.data("run-status", run_status_id(item.status)),
  ]
  @core.keyed(
    item.id,
    @core.view_with_attrs(attrs, [
      @core.text(item.text),
      artifact_badge(item.artifact_ref),
    ]),
  )
}

///|
pub fn message_feed(messages : Array[Message]) -> @core.Node {
  let rows : Array[@core.Node] = []
  for item in messages {
    rows.push(message_row(item))
  }
  @core.node(
    kind="scroll-view",
    attrs=[@core.class_name("bunnia-message-feed")],
    children=rows,
  )
}

///|
pub fn windowed_message_feed(
  messages : Array[Message],
  total_count~ : Int,
  offset? : Int = 0,
) -> @core.Node {
  let rows : Array[@core.Node] = []
  for item in messages {
    rows.push(message_row(item))
  }
  @core.node(
    kind="scroll-view",
    attrs=[
      @core.class_name("bunnia-message-feed bunnia-message-feed-windowed"),
      @core.data("bunnia-list-mode", "windowed"),
      @core.data("total-count", total_count.to_string()),
      @core.data("visible-start", offset.to_string()),
      @core.data("visible-count", messages.length().to_string()),
    ],
    children=rows,
    list_total_count=total_count,
    list_visible_count=messages.length(),
  )
}

///|
pub fn tool_result_card_view(card : ToolResultCard) -> @core.Node {
  @core.keyed(
    card.id,
    @core.view_with_attrs(
      [
        @core.class_name(
          "bunnia-tool-result-card \{run_status_class(card.status)}",
        ),
        @core.data("tool-result-id", card.id),
        @core.data("tool-name", card.tool_name),
        @core.data("artifact-ref", card.artifact_ref),
        @core.data("run-status", run_status_id(card.status)),
      ],
      [
        @core.text(card.title),
        @core.text(card.summary),
        artifact_badge(card.artifact_ref),
        tool_result_action("Open", card.open_message),
        tool_result_action("Acknowledge", card.acknowledge_message),
      ],
    ),
  )
}

///|
pub fn tool_result_card_list(cards : Array[ToolResultCard]) -> @core.Node {
  let rows : Array[@core.Node] = []
  for card in cards {
    rows.push(tool_result_card_view(card))
  }
  @core.view_with_attrs([@core.class_name("bunnia-tool-result-list")], rows)
}

///|
pub fn windowed_tool_result_card_list(
  cards : Array[ToolResultCard],
  total_count~ : Int,
  offset? : Int = 0,
) -> @core.Node {
  let rows : Array[@core.Node] = []
  for card in cards {
    rows.push(tool_result_card_view(card))
  }
  @core.node(
    kind="view",
    attrs=[
      @core.class_name(
        "bunnia-tool-result-list bunnia-tool-result-list-windowed",
      ),
      @core.data("bunnia-list-mode", "windowed"),
      @core.data("total-count", total_count.to_string()),
      @core.data("visible-start", offset.to_string()),
      @core.data("visible-count", cards.length().to_string()),
    ],
    children=rows,
    list_total_count=total_count,
    list_visible_count=cards.length(),
  )
}

///|
pub fn review_controls(action : ReviewAction) -> @core.Node {
  let enabled = review_action_enabled(action)
  @core.view_with_attrs(
    [
      @core.class_name("bunnia-review \{review_state_class(action.state)}"),
      @core.data("review-id", action.id),
      @core.data("review-state", review_state_id(action.state)),
      @core.data("review-enabled", enabled.to_string()),
    ],
    [
      @core.text(action.label),
      review_button("Approve", action.approve_message, enabled),
      review_button("Reject", action.reject_message, enabled),
    ],
  )
}

///|
fn tool_result_action(label : String, message : String) -> @core.Node {
  if message == "" {
    @core.view([])
  } else {
    @core.node(
      kind="button",
      attrs=[@core.class_name("bunnia-tool-result-action")],
      events=[@core.tap(message)],
      children=[@core.text(label)],
    )
  }
}

///|
fn review_button(
  label : String,
  message : String,
  enabled : Bool,
) -> @core.Node {
  let attrs = [
    @core.class_name(
      "bunnia-review-button \{review_button_disabled_class(enabled)}",
    ),
  ]
  if !enabled {
    attrs.push(@core.attr("disabled", "true"))
    attrs.push(@core.data("disabled", "true"))
  }
  let events = if enabled { [@core.tap(message)] } else { [] }
  @core.node(kind="button", attrs~, events~, children=[@core.text(label)])
}

///|
fn review_button_disabled_class(enabled : Bool) -> String {
  if enabled {
    "bunnia-review-button-enabled"
  } else {
    "bunnia-review-button-disabled"
  }
}

///|
fn artifact_badge(artifact_ref : String) -> @core.Node {
  if artifact_ref == "" {
    @core.view([])
  } else {
    @core.view_with_attrs(
      [
        @core.class_name("bunnia-artifact-link"),
        @core.data("artifact-ref", artifact_ref),
      ],
      [@core.text("artifact")],
    )
  }
}

///|
pub fn run_status_id(status : RunStatus) -> String {
  match status {
    Idle => "idle"
    Running => "running"
    WaitingReview => "waiting-review"
    Done => "done"
    Failed => "failed"
    Cancelled => "cancelled"
  }
}

///|
pub fn review_state_id(state : ReviewState) -> String {
  match state {
    NotRequired => "not-required"
    Pending => "pending"
    Approved => "approved"
    Rejected => "rejected"
    CancelledReview => "cancelled"
    FailedReview => "failed"
  }
}

///|
fn run_status_class(status : RunStatus) -> String {
  "bunnia-run-\{run_status_id(status)}"
}

///|
fn review_state_class(state : ReviewState) -> String {
  "bunnia-review-\{review_state_id(state)}"
}