import hashlib
import json
import time

class AuditLogEntry:
    """
    Represents a single entry in the audit log.  Each entry is hash-chained
    to the previous entry to ensure immutability.
    """
    def __init__(self, data, previous_hash):
        """
        Initializes a new audit log entry.

        Args:
            data: The data to be logged (e.g., decision record, event).  Must be JSON serializable.
            previous_hash: The hash of the previous entry in the chain.
        """
        self.timestamp = time.time()
        self.data = data
        self.previous_hash = previous_hash
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        """
        Calculates the SHA-256 hash of the entry.  Includes timestamp, data, and previous hash.
        """
        data_string = json.dumps({
            'timestamp': self.timestamp,
            'data': self.data,
            'previous_hash': self.previous_hash
        }, sort_keys=True).encode('utf-8') # Consistent serialization for hashing
        return hashlib.sha256(data_string).hexdigest()

    def __repr__(self):
        return f"AuditLogEntry(timestamp={self.timestamp}, data={self.data}, hash={self.hash}, previous_hash={self.previous_hash})"


class AuditTrail:
    """
    Manages the audit trail, providing methods for adding entries, validating the chain,
    and reconstructing decision history.
    """
    def __init__(self):
        """
        Initializes an empty audit trail with a genesis block.
        """
        self.chain = [self.create_genesis_block()]

    def create_genesis_block(self):
        """
        Creates the first block in the chain (genesis block).  Contains placeholder data.
        """
        return AuditLogEntry("Genesis Block", "0")  # "0" indicates no previous block

    def add_entry(self, data):
        """
        Adds a new entry to the audit trail.

        Args:
            data: The data to be logged (e.g., decision record, event).  Must be JSON serializable.
        """
        previous_hash = self.chain[-1].hash
        new_entry = AuditLogEntry(data, previous_hash)
        self.chain.append(new_entry)

    def is_valid(self):
        """
        Validates the integrity of the audit trail by checking the hash chain.

        Returns:
            True if the chain is valid, False otherwise.
        """
        for i in range(1, len(self.chain)):
            current_entry = self.chain[i]
            previous_entry = self.chain[i - 1]

            if current_entry.hash != current_entry.calculate_hash():
                print(f"Data corruption detected in entry {i} (hash mismatch).")
                return False

            if current_entry.previous_hash != previous_entry.hash:
                print(f"Chain break detected at entry {i} (previous hash mismatch).")
                return False

        return True

    def reconstruct_history(self):
        """
        Reconstructs the decision history from the audit trail.  Returns a list of data entries.
        """
        history = []
        for entry in self.chain[1:]:  # Skip genesis block
            history.append(entry.data)
        return history

    def query_data(self, search_term):
        """
        Queries the audit trail for entries containing the specified search term.

        Args:
            search_term: The term to search for in the data entries.

        Returns:
            A list of audit log entries that contain the search term in their data.
        """
        results = []
        for entry in self.chain:
            if search_term in str(entry.data): # Search within the data
                results.append(entry)
        return results

# Example Usage
if __name__ == '__main__':
    audit_trail = AuditTrail()

    # Add some audit log entries
    audit_trail.add_entry({"decision": "approve_loan", "user": "Alice", "amount": 10000})
    audit_trail.add_entry({"decision": "reject_loan", "user": "Bob", "amount": 5000})
    audit_trail.add_entry({"event": "account_created", "user": "Charlie"})

    # Validate the audit trail
    if audit_trail.is_valid():
        print("Audit trail is valid.")
    else:
        print("Audit trail is compromised!")

    # Reconstruct the decision history
    history = audit_trail.reconstruct_history()
    print("\nDecision History:")
    for entry in history:
        print(entry)

    # Query the audit trail
    search_results = audit_trail.query_data("loan")
    print("\nSearch Results for 'loan':")
    for entry in search_results:
        print(entry)

    # Tamper with the audit trail (for demonstration purposes)
    print("\nTampering with the audit trail...")
    audit_trail.chain[1].data = {"decision": "approve_loan", "user": "Alice", "amount": 20000}  # Modify the amount
    audit_trail.chain[1].hash = audit_trail.chain[1].calculate_hash() # Recalculate hash ONLY for modified entry.

    # Validate the audit trail again
    if audit_trail.is_valid():
        print("Audit trail is valid.")
    else:
        print("Audit trail is compromised!")
