"""
Unit Tests for Merkle Tree

Tests Merkle tree construction, proof generation, and verification.
"""

import pytest
from altrus.core.ledger.merkle import MerkleTree, create_merkle_root


class TestMerkleTree:
    """Test suite for MerkleTree"""

    def test_single_item(self):
        """Test Merkle tree with single item"""
        tree = MerkleTree(["data1"])
        assert tree.root is not None
        assert len(tree.root) == 64  # SHA-256 hex length

    def test_multiple_items(self):
        """Test Merkle tree with multiple items"""
        tree = MerkleTree(["data1", "data2", "data3", "data4"])
        assert tree.root is not None

    def test_odd_number_of_items(self):
        """Test Merkle tree with odd number of items"""
        tree = MerkleTree(["data1", "data2", "data3"])
        assert tree.root is not None

    def test_deterministic_root(self):
        """Test that same data produces same root"""
        tree1 = MerkleTree(["a", "b", "c"])
        tree2 = MerkleTree(["a", "b", "c"])

        assert tree1.root == tree2.root

    def test_different_data_different_root(self):
        """Test that different data produces different root"""
        tree1 = MerkleTree(["a", "b", "c"])
        tree2 = MerkleTree(["a", "b", "d"])

        assert tree1.root != tree2.root

    def test_generate_proof_existing_item(self):
        """Test proof generation for existing item"""
        tree = MerkleTree(["data1", "data2", "data3", "data4"])

        proof = tree.generate_proof("data2")

        assert proof is not None
        assert proof.root_hash == tree.root
        assert len(proof.proof_hashes) > 0

    def test_generate_proof_nonexistent_item(self):
        """Test proof generation for non-existent item"""
        tree = MerkleTree(["data1", "data2", "data3"])

        proof = tree.generate_proof("data_not_in_tree")

        assert proof is None

    def test_verify_valid_proof(self):
        """Test verification of valid proof"""
        tree = MerkleTree(["data1", "data2", "data3", "data4"])

        proof = tree.generate_proof("data3")

        is_valid = MerkleTree.verify_proof(proof, "data3")
        assert is_valid is True

    def test_verify_invalid_proof_wrong_data(self):
        """Test verification fails with wrong data"""
        tree = MerkleTree(["data1", "data2", "data3", "data4"])

        proof = tree.generate_proof("data3")

        # Try to verify with different data
        is_valid = MerkleTree.verify_proof(proof, "wrong_data")
        assert is_valid is False

    def test_verify_tampered_proof(self):
        """Test verification fails with tampered proof"""
        tree = MerkleTree(["data1", "data2", "data3", "data4"])

        proof = tree.generate_proof("data2")

        # Tamper with proof
        if proof.proof_hashes:
            proof.proof_hashes[0] = ("tampered_hash", proof.proof_hashes[0][1])

        is_valid = MerkleTree.verify_proof(proof, "data2")
        assert is_valid is False

    def test_create_merkle_root_convenience(self):
        """Test convenience function for creating root"""
        root = create_merkle_root(["a", "b", "c"])

        assert root is not None
        assert len(root) == 64

    def test_create_merkle_root_empty(self):
        """Test convenience function with empty list"""
        root = create_merkle_root([])

        # Should return hash of empty string
        assert root is not None
        assert len(root) == 64

    def test_proof_for_all_items(self):
        """Test that proofs can be generated for all items"""
        data = ["item1", "item2", "item3", "item4", "item5"]
        tree = MerkleTree(data)

        for item in data:
            proof = tree.generate_proof(item)
            assert proof is not None

            is_valid = MerkleTree.verify_proof(proof, item)
            assert is_valid is True


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
