#!/usr/bin/env python3
"""
CCIP Monitor Service
Monitors CCIP message flow, latency, fees, and errors
"""

import os
import time
import logging
from typing import Dict, Any, Optional
from datetime import datetime
from web3 import Web3
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import requests

# OpenTelemetry instrumentation (optional)
try:
    from opentelemetry_instrumentation import setup_tracing
    tracer = setup_tracing()
    TRACING_ENABLED = True
except ImportError:
    TRACING_ENABLED = False
    tracer = None

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Prometheus metrics
ccip_messages_sent = Counter('ccip_messages_sent_total', 'Total CCIP messages sent', ['target_chain'])
ccip_messages_success = Counter('ccip_messages_success_total', 'Total successful CCIP messages', ['target_chain'])
ccip_messages_failed = Counter('ccip_messages_failed_total', 'Total failed CCIP messages', ['target_chain'])
ccip_message_latency = Histogram('ccip_message_latency_seconds', 'CCIP message delivery latency', ['target_chain'], buckets=[1, 5, 10, 30, 60, 120, 300, 600])
ccip_fees_total = Counter('ccip_fees_total', 'Total CCIP fees paid', ['target_chain'])
ccip_link_balance = Gauge('ccip_link_balance', 'LINK token balance in CCIP sender contract')
ccip_errors_total = Counter('ccip_errors_total', 'Total CCIP errors', ['error_type'])
ccip_messages_pending = Gauge('ccip_messages_pending_total', 'Number of pending CCIP messages')
ccip_fee_calculation_errors = Counter('ccip_fee_calculation_errors_total', 'CCIP fee calculation errors')


class CCIPMonitor:
    """Monitor CCIP message flow and metrics"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.w3 = Web3(Web3.HTTPProvider(config['rpc_url']))
        self.sender_address = config['sender_address']
        self.receiver_address = config.get('receiver_address')
        self.link_token_address = config['link_token_address']
        self.last_message_id = None
        self.message_times = {}  # Track message send times
        
    def get_link_balance(self) -> float:
        """Get LINK token balance"""
        try:
            # ERC20 balanceOf(address) function
            balance = self.w3.eth.call({
                'to': self.link_token_address,
                'data': self.w3.keccak(text='balanceOf(address)')[:4].hex() + 
                        self.sender_address[2:].zfill(64)
            })
            balance_wei = int(balance.hex(), 16)
            balance_link = balance_wei / 1e18
            return balance_link
        except Exception as e:
            logger.error(f"Error getting LINK balance: {e}")
            return 0.0
    
    def monitor_messages(self):
        """Monitor CCIP messages from contract events"""
        try:
            # Get recent MessageSent events
            # This would require the CCIP contract ABI
            # For now, we'll use a placeholder
            
            # Update LINK balance
            balance = self.get_link_balance()
            ccip_link_balance.set(balance)
            
            logger.info(f"LINK balance: {balance} LINK")
            
        except Exception as e:
            logger.error(f"Error monitoring messages: {e}")
            ccip_errors_total.labels(error_type='monitoring').inc()
    
    def record_message_sent(self, target_chain: str, message_id: str):
        """Record message sent"""
        ccip_messages_sent.labels(target_chain=target_chain).inc()
        self.message_times[message_id] = time.time()
        self.last_message_id = message_id
    
    def record_message_success(self, target_chain: str, message_id: str):
        """Record successful message delivery"""
        ccip_messages_success.labels(target_chain=target_chain).inc()
        if message_id in self.message_times:
            latency = time.time() - self.message_times[message_id]
            ccip_message_latency.labels(target_chain=target_chain).observe(latency)
            del self.message_times[message_id]
    
    def record_message_failed(self, target_chain: str, message_id: str, error: str):
        """Record failed message"""
        ccip_messages_failed.labels(target_chain=target_chain).inc()
        ccip_errors_total.labels(error_type=error).inc()
        if message_id in self.message_times:
            del self.message_times[message_id]
    
    def record_fee_paid(self, target_chain: str, amount: float):
        """Record fee payment"""
        ccip_fees_total.labels(target_chain=target_chain).inc(amount)
    
    def run(self):
        """Main monitoring loop"""
        logger.info("Starting CCIP monitor...")
        
        # Start Prometheus metrics server
        start_http_server(self.config.get('metrics_port', 8000))
        logger.info(f"Metrics server started on port {self.config.get('metrics_port', 8000)}")
        
        while True:
            try:
                self.monitor_messages()
                time.sleep(self.config.get('poll_interval', 30))
            except KeyboardInterrupt:
                logger.info("Stopping CCIP monitor...")
                break
            except Exception as e:
                logger.error(f"Error in monitoring loop: {e}")
                time.sleep(5)


if __name__ == '__main__':
    config = {
        'rpc_url': os.getenv('RPC_URL', 'http://localhost:8545'),
        'sender_address': os.getenv('CCIP_SENDER_ADDRESS', ''),
        'receiver_address': os.getenv('CCIP_RECEIVER_ADDRESS', ''),
        'link_token_address': os.getenv('LINK_TOKEN_ADDRESS', ''),
        'metrics_port': int(os.getenv('METRICS_PORT', '8000')),
        'poll_interval': int(os.getenv('POLL_INTERVAL', '30'))
    }
    
    monitor = CCIPMonitor(config)
    monitor.run()

