from unittest import TestCase

from io import BytesIO

from buidl.block import Block
from buidl.helper import decode_base58
from buidl.network import (
    FILTERED_BLOCK_DATA_TYPE,
    GetDataMessage,
    GetHeadersMessage,
    HeadersMessage,
    NetworkEnvelope,
    SimpleNode,
    VersionMessage,
)


class NetworkEnvelopeTest(TestCase):
    def test_parse(self):
        msg = bytes.fromhex("f9beb4d976657261636b000000000000000000005df6e0e2")
        stream = BytesIO(msg)
        envelope = NetworkEnvelope.parse(stream)
        self.assertEqual(envelope.command, b"verack")
        self.assertEqual(envelope.payload, b"")
        msg = bytes.fromhex(
            "f9beb4d976657273696f6e0000000000650000005f1a69d2721101000100000000000000bc8f5e5400000000010000000000000000000000000000000000ffffc61b6409208d010000000000000000000000000000000000ffffcb0071c0208d128035cbc97953f80f2f5361746f7368693a302e392e332fcf05050001"
        )
        stream = BytesIO(msg)
        envelope = NetworkEnvelope.parse(stream)
        self.assertEqual(envelope.command, b"version")
        self.assertEqual(envelope.payload, msg[24:])

    def test_serialize(self):
        msg = bytes.fromhex("f9beb4d976657261636b000000000000000000005df6e0e2")
        stream = BytesIO(msg)
        envelope = NetworkEnvelope.parse(stream)
        self.assertEqual(envelope.serialize(), msg)
        msg = bytes.fromhex(
            "f9beb4d976657273696f6e0000000000650000005f1a69d2721101000100000000000000bc8f5e5400000000010000000000000000000000000000000000ffffc61b6409208d010000000000000000000000000000000000ffffcb0071c0208d128035cbc97953f80f2f5361746f7368693a302e392e332fcf05050001"
        )
        stream = BytesIO(msg)
        envelope = NetworkEnvelope.parse(stream)
        self.assertEqual(envelope.serialize(), msg)


class VersionMessageTest(TestCase):
    def test_serialize(self):
        v = VersionMessage(timestamp=0, nonce=b"\x00" * 8)
        self.assertEqual(
            v.serialize().hex(),
            "7f11010000000000000000000000000000000000000000000000000000000000000000000000ffff000000008d20000000000000000000000000000000000000ffff000000008d2000000000000000001b2f70726f6772616d6d696e67626c6f636b636861696e3a302e312f0000000001",
        )


class GetHeadersMessageTest(TestCase):
    def test_serialize(self):
        block_hex = "0000000000000000001237f46acddf58578a37e213d2a6edc4884a2fcad05ba3"
        gh = GetHeadersMessage(start_block=bytes.fromhex(block_hex))
        self.assertEqual(
            gh.serialize().hex(),
            "7f11010001a35bd0ca2f4a88c4eda6d213e2378a5758dfcd6af437120000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        )


class HeadersMessageTest(TestCase):
    def test_parse(self):
        hex_msg = "0200000020df3b053dc46f162a9b00c7f0d5124e2676d47bbe7c5d0793a500000000000000ef445fef2ed495c275892206ca533e7411907971013ab83e3b47bd0d692d14d4dc7c835b67d8001ac157e670000000002030eb2540c41025690160a1014c577061596e32e426b712c7ca00000000000000768b89f07044e6130ead292a3f51951adbd2202df447d98789339937fd006bd44880835b67d8001ade09204600"
        stream = BytesIO(bytes.fromhex(hex_msg))
        headers = HeadersMessage.parse(stream)
        self.assertEqual(len(headers.headers), 2)
        for b in headers.headers:
            self.assertEqual(b.__class__, Block)


class GetDataMessageTest(TestCase):
    def test_serialize(self):
        hex_msg = "020300000030eb2540c41025690160a1014c577061596e32e426b712c7ca00000000000000030000001049847939585b0652fba793661c361223446b6fc41089b8be00000000000000"
        get_data = GetDataMessage()
        block1 = bytes.fromhex(
            "00000000000000cac712b726e4326e596170574c01a16001692510c44025eb30"
        )
        get_data.add_data(FILTERED_BLOCK_DATA_TYPE, block1)
        block2 = bytes.fromhex(
            "00000000000000beb88910c46f6b442312361c6693a7fb52065b583979844910"
        )
        get_data.add_data(FILTERED_BLOCK_DATA_TYPE, block2)
        self.assertEqual(get_data.serialize().hex(), hex_msg)


# FIXME: make this work
# Getting:  ConnectionRefusedError: [Errno 61] Connection refused
if False:

    class SimpleNodeTest(TestCase):
        def test_handshake(self):
            node = SimpleNode("tbtc.programmingblockchain.com", testnet=True)
            node.handshake()

        def test_get_filtered_txs(self):
            from buidl.bloomfilter import BloomFilter

            bf = BloomFilter(30, 5, 90210)
            h160 = decode_base58("mseRGXB89UTFVkWJhTRTzzZ9Ujj4ZPbGK5")
            bf.add(h160)
            node = SimpleNode("tbtc.programmingblockchain.com", testnet=True)
            node.handshake()
            node.send(bf.filterload())
            block_hash = bytes.fromhex(
                "00000000000377db7fde98411876c53e318a395af7304de298fd47b7c549d125"
            )
            txs = node.get_filtered_txs([block_hash])
            self.assertEqual(
                txs[0].id(),
                "0c024b9d3aa2ae8faae96603b8d40c88df2fc6bf50b3f446295206f70f3cf6ad",
            )
            self.assertEqual(
                txs[1].id(),
                "0886537e27969a12478e0d33707bf6b9fe4fdaec8d5d471b5304453b04135e7e",
            )
            self.assertEqual(
                txs[2].id(),
                "23d4effc88b80fb7dbcc2e6a0b0af9821c6fe3bb4c8dc3b61bcab7c45f0f6888",
            )
