namespace Bliku.Tui.Terminal

/-- Cached terminal size to avoid spawning `stty` every frame. -/
initialize terminalSizeCache : IO.Ref (Option (Nat × Nat)) ← IO.mkRef none

private def parseEnvSize : IO (Option (Nat × Nat)) := do
  let rows? ← IO.getEnv "LINES"
  let cols? ← IO.getEnv "COLUMNS"
  match (rows?.bind String.toNat?, cols?.bind String.toNat?) with
  | (some r, some c) =>
      if r > 0 && c > 0 then
        return some (r, c)
      else
        return none
  | _ => return none

/-- Get terminal size (rows, cols). -/
def getWindowSize : IO (Nat × Nat) := do
  if let some sz ← terminalSizeCache.get then
    return sz
  if let some sz ← parseEnvSize then
    terminalSizeCache.set (some sz)
    return sz
  try
    let out ← IO.Process.run { cmd := "stty", args := #["-F", "/dev/tty", "size"] }
    let parts := out.trimAscii.toString.splitOn " "
    let sz := match parts with
      | [rows, cols] =>
          match (rows.toNat?, cols.toNat?) with
          | (some r, some c) =>
              if r > 0 && c > 0 then (r, c) else (24, 80)
          | _ => (24, 80)
      | _ => (24, 80)
    terminalSizeCache.set (some sz)
    return sz
  catch _ =>
    return (24, 80)

def moveCursorStr (row col : Nat) : String :=
  s!"\x1b[{row + 1};{col + 1}H"

def hideCursorStr : String := "\x1b[?25l"
def showCursorStr : String := "\x1b[?25h"
def clearLineStr : String := "\x1b[K"
def homeCursorStr : String := "\x1b[H"
def clearScreenStr : String := "\x1b[2J"

end Bliku.Tui.Terminal