# Fusabi TUI Bindings Documentation

## Overview

The Fusabi TUI bindings enable F# scripts to use terminal UI components by exposing:

1. **Formatting functions** - Pure functions for human-readable data formatting
2. **Widget specification builders** - Functions to create JSON-serializable widget configurations

## Limitations

Due to Fusabi's current `Rc<RefCell<T>>` architecture (not `Send + Sync`), full widget lifecycle management in Fusabi is not supported. This means:

- **Cannot** create and render widgets directly from F# scripts
- **Cannot** manage TUI event loops in Fusabi
- **Cannot** pass widget instances across async boundaries

### Workaround Strategy

Instead of managing widgets directly, we use a **specification-based approach**:

1. F# scripts build **widget specifications** (data structures)
2. Specifications are JSON-serializable
3. The Rust application interprets specifications and renders widgets

This pattern keeps Fusabi scripts declarative while Rust handles rendering.

## Available Functions

### Formatting Functions

All formatting functions take a single `int` argument and return a `string`.

#### `tui_format_number(n: int) -> string`

Formats large numbers with K/M/B suffixes.

```fsharp
tui_format_number 999L           // "999"
tui_format_number 1500L          // "1.50K"
tui_format_number 2500000L       // "2.50M"
tui_format_number 3500000000L    // "3.50B"
```

#### `tui_format_bytes(bytes: int) -> string`

Formats byte sizes with binary units (KB/MB/GB).

```fsharp
tui_format_bytes 512L            // "512 B"
tui_format_bytes 2048L           // "2.00 KB"
tui_format_bytes 5242880L        // "5.00 MB"
tui_format_bytes 3221225472L     // "3.00 GB"
```

#### `tui_format_latency(microseconds: int) -> string`

Formats latency from microseconds to appropriate unit (μs/ms/s).

```fsharp
tui_format_latency 500L          // "500μs"
tui_format_latency 1500L         // "1.50ms"
tui_format_latency 2500000L      // "2.50s"
```

#### `tui_format_duration(seconds: int) -> string`

Formats duration in seconds to human-readable format (s/m/h).

```fsharp
tui_format_duration 42L          // "42s"
tui_format_duration 312L         // "5m 12s"
tui_format_duration 9045L        // "2h 30m 45s"
```

### Table Specification Functions

These functions build table specifications that can be serialized and interpreted by Rust.

#### `tui_table_spec_new() -> record`

Creates an empty table specification.

```fsharp
let table = tui_table_spec_new ()
```

Returns a record with fields:
- `columns`: array of column definitions (initially empty)
- `rows`: array of data rows (initially empty)
- `title`: optional title (initially `Unit`)
- `borders`: boolean (default `true`)

#### `tui_table_add_column(spec: record, header: string, width: int) -> record`

Adds a column definition to the table specification.

**Parameters:**
- `spec`: The table specification record
- `header`: Column header text
- `width`: Column width as percentage (0-100)

```fsharp
let table = tui_table_spec_new ()
let table = tui_table_add_column table "Name" 40L
let table = tui_table_add_column table "Value" 60L
```

#### `tui_table_add_row(spec: record, cells: array<string>) -> record`

Adds a data row to the table specification.

**Parameters:**
- `spec`: The table specification record
- `cells`: Array of cell values (strings)

```fsharp
let row1 = ["Alice"; "100"]
let table = tui_table_add_row table row1

let row2 = ["Bob"; "200"]
let table = tui_table_add_row table row2
```

#### `tui_table_set_title(spec: record, title: string) -> record`

Sets the table title.

**Parameters:**
- `spec`: The table specification record
- `title`: Title text

```fsharp
let table = tui_table_set_title table "User Statistics"
```

## Complete Examples

### Example 1: Formatted GPU Metrics

```fsharp
// Create table specification
let gpuTable = tui_table_spec_new ()
let gpuTable = tui_table_set_title gpuTable "GPU Metrics"

// Add columns
let gpuTable = tui_table_add_column gpuTable "GPU" 20L
let gpuTable = tui_table_add_column gpuTable "Memory" 30L
let gpuTable = tui_table_add_column gpuTable "Utilization" 25L
let gpuTable = tui_table_add_column gpuTable "Temperature" 25L

// Add rows with formatted data
let row1 = [
    "GPU 0"
    tui_format_bytes 8589934592L  // 8 GB
    "95%"
    "72°C"
]
let gpuTable = tui_table_add_row gpuTable row1

let row2 = [
    "GPU 1"
    tui_format_bytes 8589934592L  // 8 GB
    "87%"
    "68°C"
]
let gpuTable = tui_table_add_row gpuTable row2

// At this point, gpuTable contains a complete specification
// that the Rust application can serialize and render
```

### Example 2: Performance Metrics with Formatting

```fsharp
let perfTable = tui_table_spec_new ()
let perfTable = tui_table_set_title perfTable "Performance Metrics"

// Define columns
let perfTable = tui_table_add_column perfTable "Operation" 40L
let perfTable = tui_table_add_column perfTable "Count" 20L
let perfTable = tui_table_add_column perfTable "Avg Latency" 20L
let perfTable = tui_table_add_column perfTable "Total Time" 20L

// Sample operations data
let ops = [
    ("Matrix Multiply", 1500000L, 50L, 75L)
    ("Tensor Conv2D", 850000L, 120L, 102L)
    ("Data Transfer", 3200000L, 15L, 48L)
]

// Function to add a formatted row
let addPerfRow table (name, count, latency, duration) =
    let row = [
        name
        tui_format_number count
        tui_format_latency latency
        tui_format_duration duration
    ]
    tui_table_add_row table row

// Add all rows
let perfTable = List.fold addPerfRow perfTable ops
```

### Example 3: System Resource Monitor

```fsharp
let sysTable = tui_table_spec_new ()
let sysTable = tui_table_set_title sysTable "System Resources"

let sysTable = tui_table_add_column sysTable "Resource" 30L
let sysTable = tui_table_add_column sysTable "Used" 25L
let sysTable = tui_table_add_column sysTable "Total" 25L
let sysTable = tui_table_add_column sysTable "Uptime" 20L

// CPU row
let cpuRow = [
    "CPU Cores"
    tui_format_number 16L
    tui_format_number 64L
    tui_format_duration 259200L  // 3 days
]
let sysTable = tui_table_add_row sysTable cpuRow

// RAM row
let ramRow = [
    "RAM"
    tui_format_bytes 137438953472L   // 128 GB used
    tui_format_bytes 274877906944L   // 256 GB total
    tui_format_duration 259200L
]
let sysTable = tui_table_add_row sysTable ramRow

// GPU Memory row
let gpuMemRow = [
    "GPU Memory"
    tui_format_bytes 68719476736L    // 64 GB used
    tui_format_bytes 137438953472L   // 128 GB total
    tui_format_duration 259200L
]
let sysTable = tui_table_add_row sysTable gpuMemRow
```

## Rust Integration

### Registering Bindings

```rust
use fusabi::Engine;
use fusabi_tui::bindings::FusabiTuiModule;

let mut engine = Engine::new();
let module = FusabiTuiModule::new();
module.register(&mut engine)?;

// Now the engine can execute F# scripts using TUI functions
```

### Interpreting Table Specifications

```rust
use fusabi_tui::bindings::specs::TableSpec;
use serde_json;

// Assume you've serialized the table spec from Fusabi
let json_spec = /* get from Fusabi script output */;
let spec: TableSpec = serde_json::from_str(&json_spec)?;

// Now use spec to render with Ratatui
for column in spec.columns {
    println!("Column: {}, Width: {:?}", column.header, column.width);
}

for row in spec.rows {
    println!("Row: {:?}", row);
}
```

## Future Improvements

Once Fusabi implements `Send + Sync` for `Engine`:

1. **Direct widget management** - Create and manage widgets in F# scripts
2. **Event handling** - Handle TUI events in F# code
3. **Async rendering** - Use widgets across async boundaries
4. **Widget composition** - Build complex UIs compositionally

See `/home/beengud/raibid-labs/hibana/docs/FUSABI_SEND_SYNC_ISSUE_DRAFT.md` for the proposed upstream changes.

## Best Practices

### 1. Use Formatting Functions Consistently

Always format numbers, bytes, and times using the provided functions:

```fsharp
// Good
let memory = tui_format_bytes bytes
let count = tui_format_number operations

// Avoid
let memory = sprintf "%d bytes" bytes  // Less readable
```

### 2. Build Specifications Incrementally

Use piping to build specifications step-by-step:

```fsharp
let table =
    tui_table_spec_new ()
    |> fun t -> tui_table_set_title t "My Table"
    |> fun t -> tui_table_add_column t "Col1" 50L
    |> fun t -> tui_table_add_column t "Col2" 50L
```

### 3. Separate Data and Presentation

Keep data processing separate from UI specification:

```fsharp
// Process data
let processedData =
    rawData
    |> List.map calculateMetrics
    |> List.filter isRelevant

// Build UI specification
let table =
    processedData
    |> List.fold addRow (tui_table_spec_new ())
```

### 4. Document Specification Schemas

When building complex specifications, document the expected structure:

```fsharp
// Table schema:
// Column 1: GPU ID (string)
// Column 2: Memory Usage (formatted bytes)
// Column 3: Utilization (percentage string)
// Column 4: Temperature (string with °C)
```

## Troubleshooting

### "Function not registered" errors

Ensure the TUI module is registered before executing scripts:

```rust
let module = FusabiTuiModule::new();
module.register(&mut engine)?;  // Must be called!
```

### Type mismatch errors

Check that you're passing the correct types:

```fsharp
// Correct
tui_format_number 1000L  // int64

// Wrong
tui_format_number 1000   // int32 (may cause issues)
tui_format_number "1000" // string (error)
```

### Serialization errors

If table specifications fail to serialize:

1. Ensure all row arrays have the same length
2. Check that all cells are strings
3. Verify column count matches row cell count

## Related Documentation

- [Hibana Fusabi Integration Notes](/home/beengud/raibid-labs/hibana/docs/FUSABI_INTEGRATION_NOTES.md)
- [Fusabi Send+Sync Issue Draft](/home/beengud/raibid-labs/hibana/docs/FUSABI_SEND_SYNC_ISSUE_DRAFT.md)
- [Example F# Script](../examples/fusabi_demo.fsx)
- [Widget Specification Types](../src/bindings/specs.rs)

## License

MIT OR Apache-2.0
