import logging
import pathlib
import typing

from blender_asset_tracer import blendfile
from . import result, blocks2assets, file2blocks

log = logging.getLogger(__name__)

codes_to_skip = {
    # These blocks never have external assets:
    b'ID', b'WM', b'SN',

    # These blocks are skipped for now, until we have proof they point to
    # assets otherwise missed:
    b'GR', b'WO', b'BR', b'LS',
}


def deps(bfilepath: pathlib.Path) -> typing.Iterator[result.BlockUsage]:
    """Open the blend file and report its dependencies.

    :param bfilepath: File to open.
    """

    log.info('opening: %s', bfilepath)
    bfile = blendfile.open_cached(bfilepath)

    # Sort the asset-holding blocks so that we can iterate over them
    # in disk order, which is slightly faster than random order.
    ahb = asset_holding_blocks(file2blocks.iter_blocks(bfile))
    for block in sorted(ahb):
        yield from blocks2assets.iter_assets(block)


def asset_holding_blocks(blocks: typing.Iterable[blendfile.BlendFileBlock]) \
        -> typing.Iterator[blendfile.BlendFileBlock]:
    """Generator, yield data blocks that could reference external assets."""
    for block in blocks:
        assert isinstance(block, blendfile.BlendFileBlock)
        code = block.code

        # The longer codes are either arbitrary data or data blocks that
        # don't refer to external assets. The former data blocks will be
        # visited when we hit the two-letter datablocks that use them.
        if len(code) > 2 or code in codes_to_skip:
            continue

        yield block
