"""
Lazy dictionary table utilities for memory-efficient PETL processing.

See Also:
    docs/reference/what-is-lazy-dict-table.md
    docs/howtos/how-to-write-a-fetch-function.md
"""

import petl


class LazyDict:
    """Wraps a dict generator to yield PETL-compatible tuples lazily.

    Extracts headers from the first dictionary and converts subsequent
    dictionaries to tuples for memory-efficient PETL processing.
    """

    def __init__(self, dict_generator):
        """Initialize with a dictionary generator.

        Args:
            dict_generator: Iterator/generator yielding dictionaries
        """
        self.dict_generator = dict_generator
        self.header = None

    def __iter__(self):
        """Yield PETL-compatible tuples from dictionaries."""
        for d in self.dict_generator:
            if not self.header:
                self.header = tuple(d.keys())
                yield tuple(self.header)
            yield tuple(d.get(k) for k in self.header)


def lazy_dict_table(dict_generator):
    """Convert a dictionary generator into a memory-efficient PETL table.

    Use this instead of petl.fromdicts() for large datasets to reduce memory
    usage by 85-90% through lazy evaluation.

    Args:
        dict_generator: Iterator/generator yielding dictionaries

    Returns:
        PETL table with lazy evaluation

    Example:
        from oaa.modules.lazy_dicts import lazy_dict_table

        def fetch(connection=None, source=None, **kwargs):
            def data_generator():
                for record in api.fetch_all():
                    yield record

            return lazy_dict_table(data_generator())

    See:
        docs/reference/what-is-lazy-dict-table.md
    """
    lazy_table = LazyDict(dict_generator)
    return petl.util.materialise.cache(petl.wrap(lazy_table))
