"""Convert a HTML tree in stdin into a full KDL node tree."""

import re
from html import unescape
from sys import stdin
from typing import Generator

from kdl import Node as KdlNode
from lxml.etree import Element, iterwalk
from lxml.html import fromstring

RE_WHITESPACE = re.compile(r"\s+")


def text_nodes(data: str) -> Generator[KdlNode]:
    """Convert a potentially complex string into zero or more KDL nodes of name '-'."""
    if data == "":
        return
    for line in data.splitlines(keepends=True):
        yield KdlNode(name="-", args=[unescape(line)])


def walk_html_to_kdl(root: Element) -> Generator[KdlNode]:
    """Walk a HTML document and produce a full KDL tree representing it."""
    stack = []
    context = iterwalk(root, events=("start", "end"))
    is_root = False

    for event, elem in context:
        if event == "start":
            if str(elem.tag).lower() == "root___":
                assert not is_root
                is_root = True
                continue

            assert is_root

            new_node = KdlNode(name=str(elem.tag))

            for akey, aval in elem.attrib.items():
                new_node.props[unescape(akey)] = unescape(aval)

            if elem.text:
                text = RE_WHITESPACE.sub(" ", elem.text)

                if len(elem) > 0:
                    if text.strip():
                        new_node.nodes.extend(text_nodes(text))

                elif text.strip():
                    new_node.args.append(unescape(text))

            stack.append(new_node)

        elif event == "end":
            if str(elem.tag).lower() == "root___":
                assert is_root
                break

            assert stack

            finished_node = stack.pop()

            if len(stack) > 0:
                parent = stack[-1]
                parent.nodes.append(finished_node)

                if elem.tail and elem.tail.strip("\n\r "):
                    text = RE_WHITESPACE.sub(" ", elem.tail)
                    if text.strip() or text == " ":
                        parent.nodes.extend(text_nodes(text))

            else:
                yield finished_node


def main() -> None:
    """Execute the html-to-kdl entry point."""
    root: Element = fromstring(f"<root___>{stdin.read()}</root___>")

    if root is None:
        return

    for node in walk_html_to_kdl(root):
        print(node)
