"""Check a user-supplied palette against WCAG contrast thresholds."""

from a11yviz._rules import contrast_ratio

_thresholds = {"AA": 4.5, "AAA": 7.0, "AA-large": 3.0}


def check_palette(colors, bg="#ffffff", level: str = "AA",
                  alpha: float = 1.0) -> list[dict]:
    """Check pairwise color-vs-background contrast against WCAG thresholds.

    Works on any palette: ``viridis``, ``matplotlib`` colormaps,
    ``plotly`` discrete sequences, or a custom hex list. ``bg`` defaults
    to ``"#ffffff"`` for light themes; pass a list to verify against
    multiple backgrounds (one row per color × bg pair). Use
    ``"AA-large"`` (3:1) for non-text elements such as data marks, axis
    lines, and focus rings (WCAG 2.1 Success Criterion 1.4.11).

    When ``alpha < 1``, the contrast is computed against the
    alpha-composited rendered color — the color the viewer actually
    sees. Useful when chart geoms use transparency.

    Returns a list of dicts with keys ``color``, ``bg``, ``alpha``,
    ``rendered``, ``ratio``, ``status``.
    """
    threshold = _thresholds[level]
    bgs = [bg] if isinstance(bg, str) else list(bg)
    return [
        {"color":    c,
         "bg":       b,
         "alpha":    alpha,
         "rendered": (rendered := _composite(c, b, alpha)),
         "ratio":    (r := round(contrast_ratio(rendered, b), 2)),
         "status":   "ok" if r >= threshold else "todo"}
        for b in bgs for c in colors
    ]


def _composite(fg, bg, alpha):
    if alpha == 1.0:
        return fg
    f = _hex_to_rgb(fg)
    b = _hex_to_rgb(bg)
    return "#{:02X}{:02X}{:02X}".format(
        *(round(alpha * fi + (1 - alpha) * bi) for fi, bi in zip(f, b))
    )


def _hex_to_rgb(h):
    h = h.lstrip("#")
    return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16))
