namespace Bliku.Widget

structure ListItem where
  label : String
  deriving Repr, Inhabited

structure ListProps where
  items : Array ListItem
  selected : Nat := 0
  maxVisible : Nat := 8
  width : Nat := 0
  borderLeft : String := "|"
  borderRight : String := "|"
  borderFill : Char := '-'
  selectedStyle : String := "\x1b[7m"
  resetStyle : String := "\x1b[0m"
  deriving Inhabited

structure ListBox where
  lines : Array String
  width : Nat
  height : Nat
  deriving Inhabited

def renderListBox (props : ListProps) : ListBox := Id.run do
  if props.items.isEmpty then
    return { lines := #[], width := 0, height := 0 }
  let visibleCount := min props.maxVisible props.items.size
  let labels := props.items.extract 0 visibleCount |>.map ListItem.label
  let naturalW := labels.foldl (fun acc s => max acc s.length) 0
  let innerWidth := max 1 (if props.width == 0 then naturalW else props.width)
  let border := props.borderLeft ++ "".pushn props.borderFill innerWidth ++ props.borderRight
  let selected := if props.selected < visibleCount then props.selected else 0
  let mut out : Array String := #[border]
  for i in [0:visibleCount] do
    let label := (labels[i]!.take innerWidth).toString
    let pad := if label.length < innerWidth then "".pushn ' ' (innerWidth - label.length) else ""
    let body :=
      if i == selected then
        props.selectedStyle ++ label ++ pad ++ props.resetStyle
      else
        label ++ pad
    out := out.push (props.borderLeft ++ body ++ props.borderRight)
  out := out.push border
  return { lines := out, width := innerWidth + props.borderLeft.length + props.borderRight.length, height := out.size }

end Bliku.Widget