from collections.abc import Iterator

VALID_HTML_CONTEXTS: dict[tuple[str, str], str] = {
    # https://html.spec.whatwg.org/multipage/indices.html#elements-3
    ("a", "phrasing"): "transparent",
    ("abbr", "phrasing"): "phrasing",
    ("address", "flow"): "flow",
    ("area", "phrasing"): "void",
    ("article", "flow"): "flow",
    ("aside", "flow"): "flow",
    ("audio", "phrasing"): "<audio>",
    ("b", "phrasing"): "phrasing",
    ("base", "<head>"): "void",
    ("bdi", "phrasing"): "phrasing",
    ("bdo", "phrasing"): "phrasing",
    ("blockquote", "flow"): "flow",
    ("body", "<html>"): "flow",
    ("br", "phrasing"): "void",
    ("button", "phrasing"): "phrasing",
    ("button", "<select>"): "phrasing",
    ("canvas", "phrasing"): "transparent",
    ("caption", "<table>"): "flow",
    ("center", "flow"): "flow",  # FIXME: obsolete, remove this
    ("cite", "phrasing"): "phrasing",
    ("code", "phrasing"): "phrasing",
    ("col", "<colgroup>"): "void",
    ("colgroup", "<table>"): "<colgroup>",
    ("data", "phrasing"): "phrasing",
    ("datalist", "phrasing"): "<datalist>",
    ("dd", "<dl>"): "flow",
    ("del", "phrasing"): "transparent",
    ("details", "flow"): "<details>",
    ("dfn", "phrasing"): "phrasing",
    ("dialog", "flow"): "flow",
    ("div", "flow"): "flow",
    ("div", "<dl>"): "<dl>",
    ("div", "<select> content"): "<select> content",
    ("div", "<optgroup> content"): "<optgroup> content",
    ("div", "<option> content"): "<option> content",
    ("dl", "flow"): "<dl>",
    ("dt", "<dl>"): "phrasing",
    ("em", "phrasing"): "phrasing",
    ("embed", "phrasing"): "void",
    ("fieldset", "flow"): "<fieldset>",
    ("figcaption", "<figure>"): "flow",
    ("figure", "flow"): "<figure>",
    ("footer", "flow"): "flow",
    ("form", "flow"): "flow",
    ("h1", "plain heading"): "phrasing",
    ("h2", "plain heading"): "phrasing",
    ("h3", "plain heading"): "phrasing",
    ("h4", "plain heading"): "phrasing",
    ("h5", "plain heading"): "phrasing",
    ("h6", "plain heading"): "phrasing",
    ("head", "<html>"): "<head>",
    ("header", "flow"): "flow",
    ("hgroup", "heading"): "<hgroup>",
    ("hr", "flow"): "void",
    ("hr", "<select> content"): "void",
    ("html", "document"): "<html>",
    ("i", "phrasing"): "phrasing",
    ("iframe", "phrasing"): "empty",
    ("img", "phrasing"): "void",
    ("img", "<picture>"): "void",
    ("input", "phrasing"): "void",
    ("ins", "phrasing"): "transparent",
    ("kbd", "phrasing"): "phrasing",
    ("label", "phrasing"): "phrasing",
    ("legend", "<fieldset>"): "phrasing/heading",
    ("li", "list"): "flow",
    ("link", "<head>"): "void",
    ("link", "phrasing"): "void",
    ("main", "flow"): "flow",
    ("map", "phrasing"): "<map>",
    ("mark", "phrasing"): "phrasing",
    ("math", "phrasing"): "MathML",
    ("menu", "flow"): "list",
    ("meta", "<head>"): "void",
    ("meta", "phrasing"): "void",
    ("meter", "phrasing"): "phrasing",
    ("nav", "flow"): "flow",
    ("noscript", "<head>"): "transparent",
    ("noscript", "phrasing"): "transparent",
    ("noscript", "<select> content"): "transparent",
    ("noscript", "<optgroup> content"): "transparent",
    ("object", "phrasing"): "transparent",
    ("ol", "flow"): "list",
    ("optgroup", "<select>"): "<optgroup> content",
    ("option", "<select>"): "<option> content",
    ("option", "<datalist>"): "<option> content",
    ("option", "<optgroup>"): "<option> content",
    ("output", "phrasing"): "phrasing",
    ("p", "flow"): "phrasing",
    ("p", "<hgroup>"): "phrasing",
    ("picture", "phrasing"): "<picture>",
    ("pre", "flow"): "phrasing",
    ("progress", "phrasing"): "phrasing",
    ("q", "phrasing"): "phrasing",
    ("rp", "<ruby>"): "phrasing",
    ("rt", "<ruby>"): "phrasing",
    ("ruby", "phrasing"): "<ruby>",
    ("s", "phrasing"): "phrasing",
    ("samp", "phrasing"): "phrasing",
    ("script", "<head>"): "<script>",
    ("script", "phrasing"): "<script>",
    ("script", "script-supporting"): "<script>",
    ("search", "flow"): "flow",
    ("section", "flow"): "flow",
    ("select", "phrasing"): "<select>",
    ("selectedcontent", "<button>"): "empty",
    ("slot", "phrasing"): "transparent",
    ("small", "phrasing"): "phrasing",
    ("source", "<picture>"): "void",
    ("source", "<video>"): "void",
    ("source", "<audio>"): "void",
    ("span", "phrasing"): "phrasing",
    ("strong", "phrasing"): "phrasing",
    ("style", "<head>"): "<style>",
    ("sub", "phrasing"): "phrasing",
    ("summary", "<details>"): "phrasing/heading",
    ("sup", "phrasing"): "phrasing",
    ("svg", "phrasing"): "SVG",
    ("table", "flow"): "<table>",
    ("tbody", "<table>"): "<tbody>",
    ("td", "<tr>"): "flow",
    ("template", "<head>"): "unknown",
    ("template", "phrasing"): "unknown",
    ("template", "script-supporting"): "unknown",
    ("template", "<colgroup>"): "unknown",
    ("textarea", "phrasing"): "text",
    ("tfoot", "<table>"): "<tfoot>",
    ("th", "<tr>"): "flow",
    ("thead", "<table>"): "<thead>",
    ("time", "phrasing"): "phrasing",
    ("title", "<head>"): "text",
    ("tr", "<table>"): "<tr>",
    ("tr", "<thead>"): "<tr>",
    ("tr", "<tbody>"): "<tr>",
    ("tr", "<tfoot>"): "<tr>",
    ("track", "<audio>"): "void",
    ("track", "<video>"): "void",
    ("u", "phrasing"): "phrasing",
    ("ul", "flow"): "list",
    ("var", "phrasing"): "phrasing",
    ("video", "phrasing"): "<video>",
    ("wbr", "phrasing"): "void",
    # https://html.spec.whatwg.org/multipage/embedded-content-other.html#mathml
    ("annotation-xml", "MathML"): "flow",
    ("mi", "MathML"): "phrasing",
    ("mo", "MathML"): "phrasing",
    ("mn", "MathML"): "phrasing",
    ("ms", "MathML"): "phrasing",
    ("mtext", "MathML"): "phrasing",
    # https://html.spec.whatwg.org/multipage/embedded-content-other.html#svg-0
    ("foreignObject", "SVG"): "flow",
    ("title", "SVG"): "phrasing",
}

HTML_CONTEXT_FALLBACKS: dict[str, list[str]] = {
    "<datalist>": ["phrasing", "script-supporting"],
    "<details>": ["flow"],
    "<dl>": ["script-supporting"],
    "<fieldset>": ["flow"],
    "<figure>": ["flow"],
    "<hgroup>": ["plain heading", "script-supporting"],
    "<optgroup> content": ["script-supporting"],
    "<option> content": ["phrasing"],
    "<option>": ["<option> content"],
    "<picture>": ["script-supporting"],
    "<ruby>": ["phrasing"],
    "<select> content": ["script-supporting"],
    "<select>": ["<select> content"],
    "<table>": ["script-supporting"],
    "<tbody>": ["script-supporting"],
    "<tfoot>": ["script-supporting"],
    "<thead>": ["script-supporting"],
    "<tr>": ["script-supporting"],
    "flow": ["phrasing", "heading"],
    "heading": ["plain heading"],
    "list": ["script-supporting"],
    "phrasing/heading": ["phrasing", "heading"],
    "unknown": ["document", "flow", "list", "<head>", "<select>", "<table>", "<tr>"],
}

FOREIGN_CONTEXTS = ["MathML", "SVG"]


def html_context_fallbacks(context: str) -> Iterator[str]:
    yield context
    for fallback_context in HTML_CONTEXT_FALLBACKS.get(context, []):
        yield from html_context_fallbacks(fallback_context)
