#!/usr/bin/env python3
"""Garlic Services - Enhanced Tor Services with Clove Security"""

import os
import sys
import time
import json
import hashlib
import hmac
import base64
import socket
import threading
import subprocess
from datetime import datetime, timezone
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes, hmac, serialization
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend

class CloveSecurity:
    """Clove-based security layer for Garlic Services"""
    
    def __init__(self, master_key=None):
        self.master_key = master_key or self.generate_master_key()
        self.clove_layers = 3  # Multi-layer clove security
        self.backend = default_backend()
        
    def generate_master_key(self):
        """Generate cryptographically secure master key"""
        return os.urandom(32)
    
    def derive_clove_key(self, clove_id, purpose='encryption'):
        """Derive key for specific clove layer"""
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=f'clove-{clove_id}-{purpose}'.encode(),
            iterations=100000,
            backend=self.backend
        )
        return kdf.derive(self.master_key)
    
    def encrypt_with_cloves(self, data, clove_id):
        """Encrypt data with multi-layer clove security"""
        encrypted = data
        for layer in range(self.clove_layers):
            key = self.derive_clove_key(f'{clove_id}-layer-{layer}')
            iv = os.urandom(16)
            cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=self.backend)
            encryptor = cipher.encryptor()
            
            # Pad data to AES block size
            padding_length = 16 - (len(encrypted) % 16)
            padded_data = encrypted + bytes([padding_length] * padding_length)
            
            encrypted = iv + encryptor.update(padded_data) + encryptor.finalize()
        
        return encrypted
    
    def decrypt_with_cloves(self, encrypted_data, clove_id):
        """Decrypt data with multi-layer clove security"""
        decrypted = encrypted_data
        
        for layer in reversed(range(self.clove_layers)):
            key = self.derive_clove_key(f'{clove_id}-layer-{layer}')
            iv = decrypted[:16]
            cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=self.backend)
            decryptor = cipher.decryptor()
            
            padded_data = decryptor.update(decrypted[16:]) + decryptor.finalize()
            padding_length = padded_data[-1]
            decrypted = padded_data[:-padding_length]
        
        return decrypted
    
    def create_clove_signature(self, data, clove_id):
        """Create cryptographic signature for clove"""
        key = self.derive_clove_key(clove_id, 'signature')
        h = hmac.HMAC(key, hashes.SHA256(), backend=self.backend)
        h.update(data)
        return h.finalize()
    
    def verify_clove_signature(self, data, signature, clove_id):
        """Verify clove signature"""
        key = self.derive_clove_key(clove_id, 'signature')
        h = hmac.HMAC(key, hashes.SHA256(), backend=self.backend)
        h.update(data)
        try:
            h.verify(signature)
            return True
        except:
            return False

class GarlicService:
    """Individual Garlic Service instance"""
    
    def __init__(self, service_id, service_port, clove_security):
        self.service_id = service_id
        self.service_port = service_port
        self.clove_security = clove_security
        self.onion_address = None
        self.garlic_address = None
        self.hidden_service_dir = f'/var/lib/tor/garlic_services/{service_id}'
        self.status = 'initializing'
        self.connections = []
        self.message_count = 0
        
    def setup_onion_service(self):
        """Setup base Tor onion service"""
        try:
            # Create hidden service directory
            os.makedirs(self.hidden_service_dir, mode=0o700, exist_ok=True)
            
            # Configure Tor hidden service
            tor_config = f'''
HiddenServiceDir {self.hidden_service_dir}
HiddenServicePort 80 127.0.0.1:{self.service_port}
HiddenServiceVersion 3
'''
            
            with open('/etc/tor/torrc', 'a') as f:
                f.write(tor_config)
            
            # Reload Tor configuration
            subprocess.run(['systemctl', 'reload', 'tor'], check=True)
            
            # Wait for onion address to be generated
            time.sleep(10)
            
            hostname_file = os.path.join(self.hidden_service_dir, 'hostname')
            if os.path.exists(hostname_file):
                with open(hostname_file, 'r') as f:
                    self.onion_address = f.read().strip()
                
                # Generate garlic address (onion + clove signature)
                clove_signature = self.clove_security.create_clove_signature(
                    self.onion_address.encode(), self.service_id
                )
                self.garlic_address = f'{self.onion_address}.garlic{base64.b16encode(clove_signature).decode()[:8].lower()}'
                
                self.status = 'active'
                return True
            
        except Exception as e:
            print(f"Failed to setup onion service: {e}")
            self.status = 'failed'
            return False
    
    def handle_connection(self, client_socket):
        """Handle incoming connection with clove security"""
        try:
            # Receive encrypted data
            encrypted_data = client_socket.recv(4096)
            
            # Extract clove ID and decrypt
            clove_id = encrypted_data[:16].hex()
            payload = encrypted_data[16:]
            
            # Verify clove signature
            signature = payload[-32:]
            message = payload[:-32]
            
            if not self.clove_security.verify_clove_signature(message, signature, clove_id):
                client_socket.send(b'INVALID_SIGNATURE')
                return
            
            # Decrypt with clove security
            decrypted_data = self.clove_security.decrypt_with_cloves(message, clove_id)
            
            # Process the request
            response = self.process_request(decrypted_data.decode())
            
            # Encrypt response with clove security
            encrypted_response = self.clove_security.encrypt_with_cloves(response.encode(), clove_id)
            response_signature = self.clove_security.create_clove_signature(encrypted_response, clove_id)
            
            # Send encrypted response
            client_socket.send(encrypted_response + response_signature)
            
            self.message_count += 1
            
        except Exception as e:
            print(f"Connection handling error: {e}")
        finally:
            client_socket.close()
    
    def process_request(self, request):
        """Process service request"""
        try:
            data = json.loads(request)
            
            if data.get('type') == 'status':
                return json.dumps({
                    'service_id': self.service_id,
                    'status': self.status,
                    'onion_address': self.onion_address,
                    'garlic_address': self.garlic_address,
                    'message_count': self.message_count,
                    'timestamp': datetime.now(timezone.utc).isoformat()
                })
            
            elif data.get('type') == 'echo':
                return json.dumps({
                    'echo': data.get('message', ''),
                    'service_id': self.service_id,
                    'timestamp': datetime.now(timezone.utc).isoformat()
                })
            
            else:
                return json.dumps({
                    'error': 'Unknown request type',
                    'service_id': self.service_id
                })
                
        except Exception as e:
            return json.dumps({'error': str(e)})
    
    def start_service(self):
        """Start the garlic service"""
        if not self.setup_onion_service():
            return False
        
        # Start local service server
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(('127.0.0.1', self.service_port))
        server_socket.listen(5)
        
        print(f"🧄 Garlic Service {self.service_id} active")
        print(f"   Onion: {self.onion_address}")
        print(f"   Garlic: {self.garlic_address}")
        print(f"   Local: 127.0.0.1:{self.service_port}")
        
        while True:
            try:
                client_socket, addr = server_socket.accept()
                client_thread = threading.Thread(
                    target=self.handle_connection,
                    args=(client_socket,)
                )
                client_thread.daemon = True
                client_thread.start()
                
            except KeyboardInterrupt:
                break
            except Exception as e:
                print(f"Service error: {e}")
        
        server_socket.close()

class GarlicServicesManager:
    """Manager for all Garlic Services"""
    
    def __init__(self):
        self.clove_security = CloveSecurity()
        self.services = {}
        self.tor_status = 'unknown'
        
    def setup_tor(self):
        """Setup and configure Tor"""
        try:
            print("🔐 Setting up Tor...")
            
            # Install Tor if not present
            subprocess.run(['dnf', 'install', '-y', 'tor'], check=True)
            
            # Enable and start Tor
            subprocess.run(['systemctl', 'enable', 'tor'], check=True)
            subprocess.run(['systemctl', 'start', 'tor'], check=True)
            
            # Wait for Tor to start
            time.sleep(5)
            
            # Check Tor status
            result = subprocess.run(['systemctl', 'is-active', 'tor'], capture_output=True, text=True)
            if result.stdout.strip() == 'active':
                self.tor_status = 'active'
                print("✅ Tor is active")
                return True
            else:
                self.tor_status = 'failed'
                print("❌ Tor failed to start")
                return False
                
        except Exception as e:
            print(f"❌ Tor setup failed: {e}")
            self.tor_status = 'failed'
            return False
    
    def create_service(self, service_id, service_port):
        """Create a new garlic service"""
        service = GarlicService(service_id, service_port, self.clove_security)
        self.services[service_id] = service
        return service
    
    def start_all_services(self):
        """Start all garlic services"""
        print(f"\n🧄 STARTING GARLIC SERVICES")
        print(f"🔐 Tor Status: {self.tor_status}")
        print(f"🛡️ Clove Security: {self.clove_security.clove_layers} layers")
        print("=" * 60)
        
        for service_id, service in self.services.items():
            service_thread = threading.Thread(
                target=service.start_service
            )
            service_thread.daemon = True
            service_thread.start()
            time.sleep(2)  # Stagger service starts
    
    def get_status(self):
        """Get status of all services"""
        return {
            'tor_status': self.tor_status,
            'clove_layers': self.clove_security.clove_layers,
            'services': {
                sid: {
                    'status': svc.status,
                    'onion_address': svc.onion_address,
                    'garlic_address': svc.garlic_address,
                    'message_count': svc.message_count
                }
                for sid, svc in self.services.items()
            },
            'timestamp': datetime.now(timezone.utc).isoformat()
        }

def main():
    """Main Garlic Services launcher"""
    print("🧄 GARLIC SERVICES - Enhanced Tor with Clove Security")
    print("📍 Toronto Server Deployment")
    print(f"🕐 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("=" * 60)
    
    manager = GarlicServicesManager()
    
    # Setup Tor
    if not manager.setup_tor():
        print("❌ Failed to setup Tor - exiting")
        return 1
    
    # Create services
    services_config = [
        ('pirate-hub', 8080),
        ('harmonic-sync', 8081),
        ('dragon-gateway', 8082),
        ('clove-auth', 8083),
        ('garlic-chat', 8084)
    ]
    
    for service_id, port in services_config:
        manager.create_service(service_id, port)
    
    # Start all services
    manager.start_all_services()
    
    print("\n🎉 ALL GARLIC SERVICES ACTIVE")
    print("🧄 Enhanced Tor connectivity with Clove security")
    print("🛡️ Multi-layer cryptographic protection")
    print("=" * 60)
    
    try:
        # Keep main thread alive
        while True:
            time.sleep(60)
            status = manager.get_status()
            print(f"\n📊 Status Update: {len([s for s in status['services'].values() if s['status'] == 'active'])} services active")
            
    except KeyboardInterrupt:
        print("\n🛑 Shutting down Garlic Services...")
    
    return 0

if __name__ == '__main__':
    exit(main())
