import struct
from typing import Set
from typing import NamedTuple, List

from chiabip158 import PyBIP158  # pylint: disable=no-name-in-module

from lbry.crypto.hash import double_sha256
from lbry.blockchain.transaction import Transaction
from lbry.blockchain.bcd_data_stream import BCDataStream


ZERO_BLOCK = bytes((0,)*32)


def create_block_filter(address_hashes: Set[bytes]) -> bytes:
    return bytes(PyBIP158([bytearray(a) for a in address_hashes]).GetEncoded())


def get_block_filter(block_filter: bytes) -> PyBIP158:
    return PyBIP158(bytearray(block_filter))


class Block(NamedTuple):
    height: int
    version: int
    file_number: int
    block_hash: bytes
    prev_block_hash: bytes
    merkle_root: bytes
    claim_trie_root: bytes
    timestamp: int
    bits: int
    nonce: int
    txs: List[Transaction]

    @staticmethod
    def from_data_stream(stream: BCDataStream, height: int, file_number: int):
        header = stream.data.read(112)
        version, = struct.unpack('<I', header[:4])
        timestamp, bits, nonce = struct.unpack('<III', header[100:112])
        tx_count = stream.read_compact_size()
        return Block(
            height=height,
            version=version,
            file_number=file_number,
            block_hash=double_sha256(header),
            prev_block_hash=header[4:36],
            merkle_root=header[36:68],
            claim_trie_root=header[68:100][::-1],
            timestamp=timestamp,
            bits=bits,
            nonce=nonce,
            txs=[
                Transaction(height=height, position=i, timestamp=timestamp).deserialize(stream)
                for i in range(tx_count)
            ]
        )

    @property
    def is_first_block(self):
        return self.prev_block_hash == ZERO_BLOCK