from logging import getLogger
from typing import Iterable

from plenum.common.constants import TXN_PAYLOAD, TXN_PAYLOAD_METADATA, \
    TXN_PAYLOAD_METADATA_DIGEST, TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST
from plenum.common.txn_util import append_payload_metadata
from plenum.test.delayers import delay_3pc
from plenum.test.helper import sdk_send_random_and_check
from plenum.test.node_catchup.helper import ensure_all_nodes_have_same_data
from plenum.test.node_request.helper import sdk_ensure_pool_functional
from plenum.test.stasher import delay_rules_without_processing
from stp_core.loop.eventually import eventually

import plenum.common.txn_util as txn_util

logger = getLogger()


def test_catchup_with_old_txn_metadata_digest_format(tdir, tconf,
                                                     looper,
                                                     txnPoolNodeSet,
                                                     sdk_pool_handle,
                                                     sdk_wallet_client,
                                                     monkeypatch):
    lagging_node = txnPoolNodeSet[-1]
    lagging_stasher = lagging_node.nodeIbStasher
    other_nodes = txnPoolNodeSet[:-1]

    # Utility
    def check_nodes_domain_ledger(nodes: Iterable, txn_count: int):
        for node in nodes:
            assert node.domainLedger.size >= txn_count

    # Patch payload metadata
    def append_old_payload_metadata(txn, frm=None, req_id=None, digest=None, payload_digest=None):
        txn = append_payload_metadata(txn, frm, req_id, digest, payload_digest)
        metadata = txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA]
        del metadata[TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST]
        metadata[TXN_PAYLOAD_METADATA_DIGEST] = payload_digest
        return txn
    monkeypatch.setattr(txn_util, 'append_payload_metadata', append_old_payload_metadata)

    # Check pool initial state
    initial_size = txnPoolNodeSet[0].domainLedger.size
    for node in txnPoolNodeSet:
        assert node.domainLedger.size == initial_size

    # Order some transactions, with one node discarding messages
    with delay_rules_without_processing(lagging_stasher, delay_3pc()):
        sdk_send_random_and_check(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_client, 10)
        looper.run(eventually(check_nodes_domain_ledger, other_nodes, initial_size + 10))
        assert lagging_node.domainLedger.size == initial_size

    # Catchup transactions and ensure that all nodes will eventually have same data
    lagging_node.start_catchup()
    ensure_all_nodes_have_same_data(looper, txnPoolNodeSet)

    # Ensure pool is still functional
    sdk_ensure_pool_functional(looper, txnPoolNodeSet, sdk_wallet_client, sdk_pool_handle)

Add test_catchup_with_old_txn_metadata_digest_format