import hashlib
import time
import json
from ecdsa import SigningKey, SECP256k1, VerifyingKey

class BlockchainEngine:
    def __init__(self):
        self.chain = []
        self.pending_transactions = []
        # Create Genesis Block (Req 1 & 4)
        self.create_block(previous_hash="0", nonce=100)
    
    def create_block(self, nonce, previous_hash, transactions=None):
        # Ensure transactions is a list of strings
        tx_list = transactions if transactions else ["Genesis"]
        block = {
            'index': len(self.chain) + 1,
            'timestamp': time.time(),
            'transactions': tx_list,
            'nonce': nonce,
            'previous_hash': previous_hash,
            'merkle_root': self.get_merkle_root(tx_list) 
        }
        self.chain.append(block)
        return block
      
    def hash_data(self, data):
        # Req 2: SHA-256 implementation
        encoded_data = json.dumps(data, sort_keys=True).encode()
        return hashlib.sha256(encoded_data).hexdigest()

    def get_merkle_root(self, transactions):
        # Req 11: Simple Merkle Tree logic
        if not transactions: return "0"
        tx_hashes = [self.hash_data(tx) for tx in transactions]
        while len(tx_hashes) > 1:
            if len(tx_hashes) % 2 != 0: tx_hashes.append(tx_hashes[-1])
            tx_hashes = [self.hash_data(tx_hashes[i] + tx_hashes[i+1]) for i in range(0, len(tx_hashes), 2)]
        return tx_hashes[0]

    def proof_of_work(self, last_nonce, difficulty=2):
        # Req 6: Mining simulation
        nonce = 0
        while self.valid_proof(last_nonce, nonce, difficulty) is False:
            nonce += 1
        return nonce

    def valid_proof(self, last_nonce, nonce, difficulty):
        guess = f'{last_nonce}{nonce}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:difficulty] == "0" * difficulty

# Req 3: Identity/Signing Functions
def create_wallet():
    priv = SigningKey.generate(curve=SECP256k1)
    pub = priv.get_verifying_key()
    return priv.to_string().hex(), pub.to_string().hex()

# Req 8 & 13: Simple Smart Contract & Payment Simulator
class SmartContractVM:
    def __init__(self):
        self.contracts = {}
        # Ensure these keys match exactly what the R app sends
        self.ledger = {"Co_A": 10000, "Co_B": 10000} 

    def execute_cross_border_payment(self, sender, receiver, amount):
        # Check if sender exists and has enough money
        if sender in self.ledger and self.ledger[sender] >= amount:
            self.ledger[sender] -= amount
            self.ledger[receiver] = self.ledger.get(receiver, 0) + amount
            return True, f"Success: Settled ${amount}. New Balance Co_A: ${self.ledger[sender]}"
        else:
            return False, f"Failed: Balance is ${self.ledger.get(sender, 0)}"

# Req 14: Supply Chain Tracker
class SupplyChainManager:
    def __init__(self):
        self.products = {} # Map ProductID -> Movement History

    def track_movement(self, product_id, location, status):
        if product_id not in self.products:
            self.products[product_id] = []
        entry = {"timestamp": time.time(), "location": location, "status": status}
        self.products[product_id].append(entry)
        return entry

# Req 9 & 12: Permissioned/Hyperledger Simulation
class PermissionedNetwork:
    def __init__(self):
        self.authorized_peers = ["Org1_Peer", "Org2_Peer"]
        self.channels = {"GlobalChannel": []}

    def validate_access(self, peer_id):
        return peer_id in self.authorized_peers
