from json import JSONEncoder
from signal import SIGCONT, SIGSTOP
from typing import IO, Iterable, Iterator

from .block import Block
from .element import BaseElement
from .logging import logger


class OutputDelegator:
    """Assemble blocks generated by elements into a status line."""

    def __init__(self, elements: Iterable[BaseElement], click_events=False) -> None:
        self.elements = list(elements)
        self.click_events = click_events

    def blocks(self) -> Iterator[Block]:
        """Yield blocks from every element."""
        for element in self.elements:
            try:
                yield from element.blocks()
            except Exception:
                logger.exception(f"exception while getting blocks for {element}")

    def process(self, file: IO[str]) -> Iterator[list[Block]]:
        """Send status lines to output and yield the originating blocks."""

        def send(line: str) -> None:
            print(line, file=file, flush=True)

        encoder = Encoder()
        send(
            encoder.encode(
                dict(
                    version=1,
                    stop_signal=SIGSTOP,
                    cont_signal=SIGCONT,
                    click_events=self.click_events,
                )
            )
        )
        send("[[]")
        while True:
            blocks = list(self.blocks())
            send(",{}".format(encoder.encode(blocks)))
            yield blocks


class Encoder(JSONEncoder):
    def default(self, o):
        return o.as_dict()


__all__ = [OutputDelegator.__name__]
