# geney/api_sections.py — Data-driven section descriptors for frontend rendering.
"""
Section descriptors tell the frontend HOW to render mechanism detail data
without the frontend needing mechanism-specific components. Each section
is a typed dict that maps to a generic React component.

When geney adds a new mechanism, it emits section descriptors alongside the
data. The frontend's DetailRenderer maps section types to components:

  stats_grid  → StatsGrid component (grid of labeled values)
  alert       → Alert component (colored banner with icon)
  bar_chart   → BarChart component (horizontal bars with labels)
  table       → DataTable component (sortable rows)
  sequence    → SequenceViewer component (monospace with highlights)
  structure   → StructureViewer component (dot-bracket + sequence)
  text        → Text paragraph
  badge_list  → Row of colored badges
  metric      → Single large number with label

The frontend only needs ~10 generic components to render ANY mechanism.
New mechanisms compose from these primitives.
"""
from __future__ import annotations

from typing import Any


def stats_grid(items: list[dict], columns: int = 4) -> dict:
    """Grid of labeled stat values.

    items: [{label, value, unit?, highlight?, subtext?}]
    """
    return {"type": "stats_grid", "columns": columns, "items": items}


def stat(label: str, value: Any, unit: str = "", highlight: bool = False,
         subtext: str = "") -> dict:
    """Single stat item for stats_grid."""
    return {"label": label, "value": value, "unit": unit,
            "highlight": highlight, "subtext": subtext}


def alert(text: str, severity: str = "info") -> dict:
    """Colored alert banner. severity: info, warning, error, success."""
    return {"type": "alert", "text": text, "severity": severity}


def bar_chart(title: str, data: list[dict], max_value: float | None = None,
              show_legend: bool = True) -> dict:
    """Horizontal bar chart. data: [{label, value, color?, group?}]"""
    return {"type": "bar_chart", "title": title, "data": data,
            "max_value": max_value, "show_legend": show_legend}


def table(title: str, columns: list[dict], rows: list[dict],
          sortable: bool = True, max_rows: int = 10) -> dict:
    """Data table. columns: [{key, label, format?}]. rows: [{key: value}]"""
    return {"type": "table", "title": title, "columns": columns,
            "rows": rows, "sortable": sortable, "max_rows": max_rows}


def sequence_viewer(label: str, sequence: str, highlights: list[dict] | None = None,
                    monospace: bool = True) -> dict:
    """Sequence display. highlights: [{start, end, color, label}]"""
    return {"type": "sequence", "label": label, "sequence": sequence,
            "highlights": highlights or [], "monospace": monospace}


def structure_viewer(label: str, sequence: str, structure: str,
                     mfe: float | None = None) -> dict:
    """RNA dot-bracket structure display."""
    return {"type": "structure", "label": label, "sequence": sequence,
            "structure": structure, "mfe": mfe}


def text(content: str) -> dict:
    """Plain text paragraph."""
    return {"type": "text", "content": content}


def badge_list(title: str, badges: list[dict]) -> dict:
    """Row of colored badges. badges: [{label, color?, tooltip?}]"""
    return {"type": "badge_list", "title": title, "badges": badges}


def metric(label: str, value: Any, unit: str = "", format: str = "",
           color: str | None = None, subtext: str = "") -> dict:
    """Single prominent metric."""
    return {"type": "metric", "label": label, "value": value,
            "unit": unit, "format": format, "color": color, "subtext": subtext}


def divider() -> dict:
    """Visual separator."""
    return {"type": "divider"}


def section_group(title: str, sections: list[dict], collapsible: bool = True,
                  default_open: bool = False) -> dict:
    """Group of sections under a header."""
    return {"type": "section_group", "title": title, "sections": sections,
            "collapsible": collapsible, "default_open": default_open}
