// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
 * @title MerkleProofVerifier
 * @notice Library for verifying Merkle proofs for trustless bridge fraud proofs
 * @dev Supports verification of deposit existence/non-existence in source chain state
 */
library MerkleProofVerifier {
    /**
     * @notice Verify a Merkle proof for deposit existence
     * @param root Merkle root from source chain state
     * @param leaf Deposit data hash (keccak256(abi.encodePacked(depositId, asset, amount, recipient, timestamp)))
     * @param proof Merkle proof path
     * @return True if proof is valid
     */
    function verifyDepositExistence(
        bytes32 root,
        bytes32 leaf,
        bytes32[] memory proof
    ) internal pure returns (bool) {
        return verify(proof, root, leaf);
    }

    /**
     * @notice Verify a Merkle proof for deposit non-existence (proof of absence)
     * @param root Merkle root from source chain state
     * @param leaf Deposit data hash
     * @param proof Merkle proof path showing absence
     * @param leftSibling Left sibling in the tree (for non-existence proofs)
     * @param rightSibling Right sibling in the tree (for non-existence proofs)
     * @return True if proof of absence is valid
     */
    function verifyDepositNonExistence(
        bytes32 root,
        bytes32 leaf,
        bytes32[] memory proof,
        bytes32 leftSibling,
        bytes32 rightSibling
    ) internal pure returns (bool) {
        // For non-existence proofs, we verify that the leaf would be between leftSibling and rightSibling
        // and that the proof path shows the leaf doesn't exist
        require(leftSibling < leaf && leaf < rightSibling, "MerkleProofVerifier: invalid sibling order");
        
        // Verify the proof path
        return verify(proof, root, leaf);
    }

    /**
     * @notice Verify a Merkle proof
     * @param proof Array of proof elements
     * @param root Merkle root
     * @param leaf Leaf hash
     * @return True if proof is valid
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash < proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        // Check if the computed hash (root) is equal to the provided root
        return computedHash == root;
    }

    /**
     * @notice Hash deposit data for Merkle tree leaf
     * @param depositId Deposit ID
     * @param asset Asset address
     * @param amount Deposit amount
     * @param recipient Recipient address
     * @param timestamp Deposit timestamp
     * @return Leaf hash
     */
    function hashDepositData(
        uint256 depositId,
        address asset,
        uint256 amount,
        address recipient,
        uint256 timestamp
    ) internal pure returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                depositId,
                asset,
                amount,
                recipient,
                timestamp
            )
        );
    }

    /**
     * @notice Verify state root against block header
     * @param blockHeader Block header bytes
     * @return True if state root matches block header
     * @dev This is a placeholder - in production, implement full block header parsing
     */
    function verifyStateRoot(
        bytes memory blockHeader,
        bytes32
    ) internal pure returns (bool) {
        // Placeholder: In production, parse RLP-encoded block header and extract state root
        // For now, require non-empty block header
        require(blockHeader.length > 0, "MerkleProofVerifier: empty block header");
        
        // TODO: Implement RLP decoding and state root extraction
        // This would involve:
        // 1. RLP decode block header
        // 2. Extract state root (at specific position in header)
        // 3. Compare with provided state root
        
        return true; // Placeholder - always return true for now
    }
}
