# src/dattos_cli/table.py
from __future__ import annotations

from typing import Any, Callable

import typer

Formatter = Callable[[Any], str] | None

_MAX_COL = 30


def truncate(value: str, max_len: int) -> str:
    """Truncate string with … if longer than max_len."""
    if max_len <= 0:
        return ""
    if len(value) <= max_len:
        return value
    return value[: max_len - 1] + "…"


def _cell(raw: Any, formatter: Formatter) -> str:
    """Render a single cell value: null guard → formatter → truncate."""
    if raw is None:
        return "—"
    text = formatter(raw) if formatter is not None else str(raw)
    return truncate(text, _MAX_COL)


def print_table(
    data: list[dict],
    columns: list[tuple[str, str, Formatter]],
    label: str = "items",
) -> None:
    """Print list as monochromatic table.

    columns = [(header, key, formatter), ...]
    Column width: max(len(header), max cell width), capped at _MAX_COL.
    None values render as "—" without calling formatter.
    """
    if not data:
        typer.echo(f"0 {label}")
        return

    # Build all cells
    rows = [
        [_cell(row.get(key), fmt) for _, key, fmt in columns]
        for row in data
    ]

    # Compute column widths
    widths = [
        max(len(header), max(len(rows[r][c]) for r in range(len(rows))))
        for c, (header, _, _) in enumerate(columns)
    ]

    # Header
    typer.echo("  ".join(header.upper().ljust(w) for (header, _, _), w in zip(columns, widths)).rstrip())

    # Separator
    typer.echo("  ".join("-" * w for w in widths).rstrip())

    # Data rows
    for row in rows:
        typer.echo("  ".join(cell.ljust(w) for cell, w in zip(row, widths)).rstrip())

    # Footer
    typer.echo(f"{len(data)} {label}")


def print_record(data: dict, exclude: list[str] | None = None) -> None:
    """Print dict as vertical key/value record. Omits None values and excluded keys."""
    exclude_set = set(exclude or [])
    visible = [(k, v) for k, v in data.items() if v is not None and k not in exclude_set]
    if not visible:
        return
    key_width = max(len(k) for k, _ in visible)
    for key, value in visible:
        typer.echo(f"{key:<{key_width}}  {value}")
