#!/usr/bin/env python3
# Copyright (c) 2024 The Bitcoin Unlimited developers

"""
Tests for offset/limit filtering
"""

import asyncio
from test_framework.electrumutil import (
    ElectrumTestFramework,
)
from test_framework.electrumconnection import ElectrumConnection


# pylint: disable=too-many-locals, too-many-arguments
class OffsetFilterTest(ElectrumTestFramework):
    async def run_test(self):
        n = self.nodes[0]
        n.generate(120)

        cli = ElectrumConnection()
        await cli.connect()
        try:
            await self.sync_height(cli)

            gen_token_addr = n.getnewaddress()
            token_id, mint_txid = await self.create_token(
                to_addr=gen_token_addr, mint_amount=1000
            )
            print("mint txid", mint_txid)
            n.generate(1)
            await self.sync_all(cli)

            confirmed_txs = []
            unconfirmed_txs = []

            # Test setup;
            # mine 10 blocks with 1 transcation each (to give it a sorting order)
            # add 10 transactions to mempool
            addr = n.getnewaddress()

            for _ in range(0, 10):
                confirmed_txs.append(await self.send_token(token_id, addr, 21))
                n.generate(1)

            for _ in range(0, 10):
                unconfirmed_txs.append(await self.send_token(token_id, addr, 21))

            await self.sync_all(cli)

            await self.test_offset_limit_filter(
                cli, addr, confirmed_txs, unconfirmed_txs
            )
            await self.test_token_offset_limit_filter(
                cli, addr, confirmed_txs, unconfirmed_txs
            )

        finally:
            cli.disconnect()

    async def test_offset_limit_filter(self, cli, addr, confirmed, unconfirmed):
        offset = 5
        limit = 5

        query_filter = {"offset": offset, "limit": limit}

        history = await cli.call("blockchain.address.get_history", addr, query_filter)
        history_len = len(history)

        assert (
            limit == history_len
        ), f"unexpected result count; expected {limit} != got {history_len}"

        expected_hashes = confirmed[offset : offset + limit]
        actual_hashes = [entry["tx_hash"] for entry in history]

        assert (
            expected_hashes == actual_hashes
        ), f"Mismatch in transaction hashes; expected {expected_hashes} != got {actual_hashes}"

        mempool_history = await cli.call(
            "blockchain.address.get_mempool", addr, query_filter
        )
        assert limit == len(
            mempool_history
        ), f"unexpected result count; expected {limit} != got {len(mempool_history)}"

        for entry in mempool_history:
            assert any(entry.get("tx_hash") == txid for txid in unconfirmed)

        print("OK")

    async def test_token_offset_limit_filter(self, cli, addr, confirmed, unconfirmed):
        offset = 5
        limit = 5

        query_filter = {"offset": offset, "limit": limit}

        history = (
            await cli.call("token.address.get_history", addr, None, None, query_filter)
        )["transactions"]
        history_len = len(history)

        assert (
            limit == history_len
        ), f"unexpected result count; expected {limit} != got {history_len}"

        expected_hashes = confirmed[offset : offset + limit]
        actual_hashes = [entry["tx_hash"] for entry in history]

        assert (
            expected_hashes == actual_hashes
        ), f"Mismatch in transaction hashes; expected {expected_hashes} != got {actual_hashes}"

        mempool_history = (
            await cli.call("token.address.get_mempool", addr, None, None, query_filter)
        )["transactions"]
        assert limit == len(
            mempool_history
        ), f"unexpected result count; expected {limit} != got {len(mempool_history)}"

        for entry in mempool_history:
            assert any(entry.get("tx_hash") == txid for txid in unconfirmed)

        print("OK")


if __name__ == "__main__":
    asyncio.run(OffsetFilterTest().main())
