"""Audit a figure against accessibility standards."""

from a11yviz._rules import check_level


def audit(fig, level: str = "AA") -> list[dict]:
    """Audit a figure against accessibility standards.

    Returns a list of dicts with keys ``criterion``, ``check``,
    ``status``, ``note``. Anchored to W3C WCAG 2.1. The ``criterion``
    field carries the success-criterion number ('1.1.1', '1.4.3',
    etc.) so the result joins cleanly to ``rubric()`` and
    ``wcag_url()``.
    """
    level    = check_level(level)
    has_alt  = bool(getattr(fig, "_a11y_alt", None))
    is_chart = (
        type(fig).__module__.startswith("plotly.")
        or type(fig).__module__.startswith("matplotlib.")
    )
    applied = "applied" if is_chart else "unknown"

    alt = ({"status": "ok",   "note": "alt text attached"} if has_alt
           else {"status": "todo", "note": "call alt_text() or alt_template()"})
    color = _check_color_only(fig)
    text  = _check_text_size(fig, level)
    hover = _check_hover(fig)

    rows = [
        _row("1.1.1",  "Alt text on figure",
             alt["status"], alt["note"]),
        _row("1.3.1",  "Heading hierarchy",
             "doc",    "run check_headings() on the host document"),
        _row("1.4.1",  "Redundant group encoding",
             color["status"], color["note"]),
        _row("1.4.3",  "Text contrast (Min)",
             applied,  "theme() / layout() set 4.5:1 text on 3:1 non-text"),
        _row("1.4.4",  f"Recommended text size ({level} default)",
             text["status"], text["note"]),
        _row("1.4.4",  "Text resizable",
             applied,  "fonts set in pt; layout scales with container"),
        _row("1.4.10", "Reflow at 320 CSS px",
             "manual", "verify the host page reflows at 320 px without 2D scroll; css_path() ships @media rules"),
        _row("1.4.11", "Non-text contrast",
             applied,  "axis lines, gridlines, error bars styled"),
        _row("1.4.12", "Body text spacing",
             "css",    "include css_path() for line-height and paragraph spacing"),
        _row("1.4.13", "Content on hover or focus",
             hover["status"], hover["note"]),
        _row("2.4.7",  "Visible keyboard focus",
             "css",    "include css_path() for keyboard focus rings"),
    ]
    aaa = [_row("1.4.6", "Enhanced text contrast (AAA)",
                applied, "AAA contrast ratios applied")]
    return rows + (aaa if level == "AAA" else [])


def _row(criterion, check, status, note):
    return {"criterion": criterion, "check": check, "status": status, "note": note}


_color_table = {
    (False, False): {"status": "n/a",
                     "note":   "no color/fill aesthetic"},
    (False, True):  {"status": "n/a",
                     "note":   "no color/fill aesthetic"},
    (True,  True):  {"status": "ok",
                     "note":   "marker symbol or line dash redundantly encodes group"},
    (True,  False): {"status": "todo",
                     "note":   "add a marker or line-dash mapping alongside color"},
}


def _check_text_size(fig, level):
    threshold = 14 if level == "AAA" else 12
    size = _extract_font_size(fig)
    if not isinstance(size, (int, float)):
        return {"status": "manual",
                "note":   f"verify text size manually (min {threshold} pt for {level})"}
    if size >= threshold:
        return {"status": "ok",
                "note":   f"base size {size} pt (min {threshold} pt)"}
    return {"status": "todo",
            "note":   f"base size {size} pt; bump to >= {threshold} pt or wrap in theme(level=\"{level}\")"}


def _extract_font_size(fig):
    if type(fig).__module__.startswith("plotly."):
        font = getattr(fig.layout, "font", None)
        return getattr(font, "size", None) if font is not None else None
    if type(fig).__module__.startswith("matplotlib."):
        try:
            import matplotlib as mpl
        except ImportError:
            return None
        return mpl.rcParams.get("font.size")
    return None


def _check_color_only(fig):
    if type(fig).__module__.startswith("plotly."):
        if not fig.data:
            return {"status": "n/a", "note": "no traces"}
        symbols = {(getattr(t, "marker", None) and getattr(t.marker, "symbol", None),
                    getattr(t, "line", None)   and getattr(t.line,   "dash",   None))
                   for t in fig.data}
        return _color_table[(True, len(symbols) > 1)]
    return {"status": "manual",
            "note":   "verify a marker or line-dash mapping accompanies color"}


def _check_hover(fig):
    if not type(fig).__module__.startswith("plotly."):
        return {"status": "n/a",
                "note":   "matplotlib output has no interactive hover tooltips"}
    hl = getattr(fig.layout, "hoverlabel", None)
    has_layout = hl is not None and getattr(hl, "bgcolor", None) is not None
    if has_layout:
        return {"status": "applied",
                "note":   "hover labels styled by layout(); verify Esc dismiss + persistent on hover"}
    return {"status": "todo",
            "note":   "call layout(); verify tooltips dismiss with Esc and persist while hovered"}
