"""Numbers shared by the widget, the figures and the lesson text. Nothing here changes the toy."""
from functools import lru_cache

from refusal_toy import LAYERS, angle, direction_at, edit_and_measure, study

SHARES = list(range(0, 101, 5))            # percent of the direction taken out
NOISE_WORDS, NOISE = ["low", "normal", "high"], [0.5, 1.0, 2.0]
SECOND = [0, 15, 30]                       # percent of flagged requests that use the second route
OPENING = {"share": 100, "layer": 5, "second": 0, "noise": 1}   # the widget opens here: the default setting of trace.py, all of the direction taken out


def run(noise=1.0, second=0.0):
    """One setting of the toy: the direction found at every layer and what taking out each share does."""
    model, sets, base = study(noise, second)
    out = {"base": int((base["test_flagged"][0].argmax(1) == 0).sum()), "angle": [], "refused": [], "changed": [], "kl": []}
    for layer in range(LAYERS + 1):
        u = direction_at(base, layer)
        results = [edit_and_measure(model, sets, base, u, share / 100) for share in SHARES]
        out["angle"].append(round(angle(u, model["routes"][0]), 1))
        out["refused"].append([r["flagged_refused"] for r in results])
        out["changed"].append([r["changed"] for r in results])
        out["kl"].append([r["kl"] for r in results])
    return out


@lru_cache(maxsize=None)
def grid():
    """Every setting the widget offers: runs[noise][second]."""
    return [[run(noise, second / 100) for second in SECOND] for noise in NOISE]


def headline(share, layer, base, refused, changed):
    """The one sentence the widget shows; widget.html builds the same words."""
    if share == 0:
        return f"Nothing taken out: {base} of 100 flagged requests are refused and no plain request changes its answer."
    state = f"{refused} of 100 flagged requests are still refused" if refused == base else f"{refused} of 100 flagged requests are refused, down from {base}"
    return f"Take out {share}% of the direction read after layer {layer} and {state}. Plain requests whose answer changes: {changed} of 100."


def describe(share, layer, second_index, noise_index):
    """What the widget shows for one setting; test_widget.py compares this with the page's own words for every setting."""
    r = grid()[noise_index][second_index]
    i = SHARES.index(share)
    return {"head": headline(share, layer, r["base"], r["refused"][layer][i], r["changed"][layer][i]),
            "angle": f"The direction found is {r['angle'][layer]:.1f} degrees from the planted one.",
            "refused": r["refused"][layer], "changed": r["changed"][layer]}


def widget_config():
    return {"shares": SHARES, "noise": NOISE_WORDS, "second": SECOND, "opening": OPENING,
            "runs": [[{k: run_[k] for k in ("base", "angle", "refused", "changed")} for run_ in row] for row in grid()]}
