import asyncio
import json
import logging
from typing import Dict, Any, List
from aiohttp import web
import json
from decimal import Decimal
from ..core.unified_mining_controller import UnifiedMiningController
from ..core.network_sync import NetworkSync
from ..mining.pipeline import BitcoinMiningPipeline
from ..utils.logger import Logger
from .database_manager import DatabaseManager
from ..core.wallet import WalletManager

class MiningVerificationServer:
    def __init__(self, miner, reward_processor, wallet, host: str = "localhost", port: int = 8080):
        self.host = host
        self.port = port
        self.logger = Logger()
        self.app = web.Application()
        self.miner = miner
        self.reward_processor = reward_processor
        self.wallet = wallet
        self.mining_controller = UnifiedMiningController()
        self.mining_pipeline = BitcoinMiningPipeline()
        self.db_manager = DatabaseManager()
        self.wallet_manager = WalletManager()
        self.network_sync = NetworkSync(self.db_manager)  # Initialize with database manager
        
        # Performance monitoring intervals (in seconds)
        self.monitoring_intervals = {
            'basic': 1,      # Basic metrics every second
            'detailed': 5,   # Detailed metrics every 5 seconds
            'thermal': 2,    # Thermal monitoring every 2 seconds
            'network': 3,    # Network metrics every 3 seconds
            'memory': 4      # Memory usage every 4 seconds
        }
        
        # Initialize monitoring tasks
        self.monitoring_tasks = {}
        
        # Historical data storage
        self.metrics_history = {
            'performance': [],
            'thermal': [],
            'memory': [],
            'network': []
        }
        
        # Alert thresholds
        self.thresholds = {
            'cpu_temp': 80,  # Celsius
            'gpu_temp': 85,  # Celsius
            'memory_usage': 90,  # Percentage
            'hash_rate_drop': 20,  # Percentage
            'power_usage': 95  # Percentage of TDP
        }
        
        # Setup routes
        self.setup_routes()
        
    def setup_routes(self):
        """Setup server routes"""
        # Basic monitoring endpoints
        self.app.router.add_get('/status', self.get_status)
        self.app.router.add_get('/performance', self.get_performance)
        self.app.router.add_get('/network', self.get_network_status)
        self.app.router.add_post('/verify/block', self.verify_block)
        self.app.router.add_get('/standards/check', self.check_standards)
        
        # Advanced monitoring endpoints
        self.app.router.add_get('/monitor/thermal', self.get_thermal_status)
        self.app.router.add_get('/monitor/memory', self.get_memory_status)
        self.app.router.add_get('/monitor/power', self.get_power_status)
        self.app.router.add_get('/monitor/hardware', self.get_hardware_details)
        self.app.router.add_get('/monitor/metrics/history', self.get_metrics_history)
        
        # Alert and threshold management
        self.app.router.add_get('/alerts', self.get_active_alerts)
        self.app.router.add_post('/alerts/configure', self.configure_alerts)
        
        # Advanced analytics
        self.app.router.add_get('/analytics/efficiency', self.get_mining_efficiency)
        self.app.router.add_get('/analytics/predictions', self.get_performance_predictions)

        # Wallet management
        self.app.router.add_get('/wallet/{address}', self.get_wallet)
        self.app.router.add_post('/wallet/create', self.create_wallet)
        self.app.router.add_put('/wallet/{address}/update', self.update_wallet)
        self.app.router.add_get('/wallet/{address}/balance', self.get_wallet_balance)
        self.app.router.add_get('/wallet/{address}/transactions', self.get_wallet_transactions)
        
        # Transaction management
        self.app.router.add_post('/transaction/create', self.create_transaction)
        self.app.router.add_get('/transaction/{tx_hash}', self.get_transaction)
        self.app.router.add_get('/transaction/{tx_hash}/status', self.get_transaction_status)
        self.app.router.add_get('/transactions/pending', self.get_pending_transactions)
        
        # Database operations
        self.app.router.add_get('/db/mining-stats', self.get_db_mining_stats)
        self.app.router.add_get('/db/wallets', self.get_all_wallets)
        self.app.router.add_get('/db/transactions', self.get_all_transactions)
        
    async def get_status(self, request: web.Request) -> web.Response:
        """Get overall mining system status"""
        try:
            stats = self.mining_controller.get_mining_stats()
            return web.json_response({
                'status': 'active',
                'mining_stats': stats,
                'timestamp': asyncio.get_event_loop().time()
            })
        except Exception as e:
            return web.json_response({
                'status': 'error',
                'error': str(e)
            }, status=500)

    async def get_performance(self, request: web.Request) -> web.Response:
        """Get detailed performance metrics"""
        try:
            cpu_status = await self._get_cpu_performance()
            gpu_status = await self._get_gpu_performance()
            
            return web.json_response({
                'cpu_performance': cpu_status,
                'gpu_performance': gpu_status,
                'total_hash_rate': cpu_status['hash_rate'] + gpu_status['hash_rate']
            })
        except Exception as e:
            return web.json_response({
                'status': 'error',
                'error': str(e)
            }, status=500)

    async def get_network_status(self, request: web.Request) -> web.Response:
        """Get network synchronization status"""
        try:
            network_status = {
                'connections': self.network_sync.get_connection_count(),
                'sync_status': 'synchronized',
                'latest_block': await self._get_latest_block_info()
            }
            return web.json_response(network_status)
        except Exception as e:
            return web.json_response({
                'status': 'error',
                'error': str(e)
            }, status=500)

    async def verify_block(self, request: web.Request) -> web.Response:
        """Verify a mined block"""
        try:
            data = await request.json()
            block_data = data.get('block_data')
            
            if not block_data:
                return web.json_response({
                    'status': 'error',
                    'error': 'No block data provided'
                }, status=400)
            
            # Verify block hash
            is_valid = self.mining_pipeline._verify_block_hash(block_data)
            
            # Verify block structure
            structure_valid = await self._verify_block_structure(block_data)
            
            return web.json_response({
                'is_valid': is_valid and structure_valid,
                'hash_valid': is_valid,
                'structure_valid': structure_valid
            })
        except Exception as e:
            return web.json_response({
                'status': 'error',
                'error': str(e)
            }, status=500)

    async def check_standards(self, request: web.Request) -> web.Response:
        """Check mining standards compliance"""
        try:
            standards_check = await self._verify_mining_standards()
            return web.json_response(standards_check)
        except Exception as e:
            return web.json_response({
                'status': 'error',
                'error': str(e)
            }, status=500)

    async def _get_cpu_performance(self) -> Dict[str, Any]:
        """Get CPU mining performance metrics"""
        stats = self.mining_controller.get_mining_stats()
        return {
            'hash_rate': stats['cpu_hash_rate'],
            'active_cores': stats.get('cpu_details', {}).get('active_cores', 0),
            'utilization': stats.get('cpu_details', {}).get('utilization', 0)
        }

    async def _get_gpu_performance(self) -> Dict[str, Any]:
        """Get GPU mining performance metrics"""
        stats = self.mining_controller.get_mining_stats()
        return {
            'hash_rate': stats['gpu_hash_rate'],
            'active_gpus': stats.get('gpu_details', {}).get('active_gpus', 0),
            'memory_usage': stats.get('gpu_details', {}).get('memory_usage', 0)
        }

    async def _get_latest_block_info(self) -> Dict[str, Any]:
        """Get information about the latest block"""
        # Implementation would depend on your blockchain node implementation
        return {
            'height': 0,  # Replace with actual implementation
            'hash': '',   # Replace with actual implementation
            'timestamp': asyncio.get_event_loop().time()
        }

    async def _verify_block_structure(self, block_data: Dict) -> bool:
        """Verify the structure of a block"""
        required_fields = ['version', 'previousblockhash', 'merkleroot', 'timestamp', 'bits', 'nonce']
        return all(field in block_data for field in required_fields)

    async def _verify_mining_standards(self) -> Dict[str, Any]:
        """Verify mining standards compliance"""
        return {
            'protocol_version': 'compliant',
            'hash_algorithm': 'SHA256',
            'network_rules': 'compliant',
            'block_structure': 'valid',
            'timestamp_checks': 'passed'
        }

    async def get_thermal_status(self, request: web.Request) -> web.Response:
        """Get detailed thermal monitoring data"""
        try:
            thermal_data = {
                'cpu': await self._get_cpu_thermal_data(),
                'gpu': await self._get_gpu_thermal_data(),
                'memory': await self._get_memory_thermal_data(),
                'ambient': await self._get_ambient_temperature(),
                'cooling_status': await self._get_cooling_status()
            }
            return web.json_response(thermal_data)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_memory_status(self, request: web.Request) -> web.Response:
        """Get detailed memory usage statistics"""
        try:
            memory_stats = {
                'system': await self._get_system_memory_stats(),
                'gpu': await self._get_gpu_memory_stats(),
                'virtual': await self._get_virtual_memory_stats(),
                'swap': await self._get_swap_usage(),
                'allocation': await self._get_memory_allocation_details()
            }
            return web.json_response(memory_stats)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_power_status(self, request: web.Request) -> web.Response:
        """Get power consumption and efficiency metrics"""
        try:
            power_stats = {
                'total_consumption': await self._get_total_power_consumption(),
                'gpu_power': await self._get_gpu_power_stats(),
                'cpu_power': await self._get_cpu_power_stats(),
                'efficiency_metrics': await self._calculate_power_efficiency(),
                'power_limits': await self._get_power_limits()
            }
            return web.json_response(power_stats)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_hardware_details(self, request: web.Request) -> web.Response:
        """Get detailed hardware information and status"""
        try:
            hardware_info = {
                'cpu_details': await self._get_detailed_cpu_info(),
                'gpu_details': await self._get_detailed_gpu_info(),
                'memory_config': await self._get_memory_configuration(),
                'cooling_system': await self._get_cooling_system_info(),
                'power_supply': await self._get_power_supply_info()
            }
            return web.json_response(hardware_info)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_metrics_history(self, request: web.Request) -> web.Response:
        """Get historical performance metrics"""
        try:
            duration = request.query.get('duration', '24h')
            metrics_type = request.query.get('type', 'all')
            
            history_data = await self._get_historical_metrics(duration, metrics_type)
            return web.json_response(history_data)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_active_alerts(self, request: web.Request) -> web.Response:
        """Get current active alerts and warnings"""
        try:
            alerts = await self._check_all_alerts()
            return web.json_response(alerts)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def configure_alerts(self, request: web.Request) -> web.Response:
        """Configure alert thresholds and notifications"""
        try:
            data = await request.json()
            updated_thresholds = await self._update_alert_thresholds(data)
            return web.json_response(updated_thresholds)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_mining_efficiency(self, request: web.Request) -> web.Response:
        """Get mining efficiency analytics"""
        try:
            efficiency_data = {
                'hash_per_watt': await self._calculate_hash_per_watt(),
                'hash_per_core': await self._calculate_hash_per_core(),
                'cost_per_hash': await self._calculate_cost_per_hash(),
                'efficiency_trends': await self._get_efficiency_trends(),
                'optimization_suggestions': await self._get_optimization_suggestions()
            }
            return web.json_response(efficiency_data)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def get_performance_predictions(self, request: web.Request) -> web.Response:
        """Get performance prediction analytics"""
        try:
            prediction_data = {
                'hash_rate_prediction': await self._predict_hash_rate(),
                'power_usage_prediction': await self._predict_power_usage(),
                'thermal_prediction': await self._predict_thermal_behavior(),
                'maintenance_prediction': await self._predict_maintenance_needs(),
                'optimization_opportunities': await self._identify_optimization_opportunities()
            }
            return web.json_response(prediction_data)
        except Exception as e:
            return web.json_response({'status': 'error', 'error': str(e)}, status=500)

    async def _start_monitoring_tasks(self):
        """Start all monitoring background tasks"""
        for metric, interval in self.monitoring_intervals.items():
            self.monitoring_tasks[metric] = asyncio.create_task(
                self._monitor_metric(metric, interval)
            )

    async def _monitor_metric(self, metric: str, interval: int):
        """Background task for monitoring specific metrics"""
        while True:
            try:
                data = await self._collect_metric_data(metric)
                self.metrics_history[metric].append({
                    'timestamp': asyncio.get_event_loop().time(),
                    'data': data
                })
                
                # Keep only last 24 hours of data
                cutoff = asyncio.get_event_loop().time() - (24 * 3600)
                self.metrics_history[metric] = [
                    m for m in self.metrics_history[metric]
                    if m['timestamp'] > cutoff
                ]
                
                # Check for alerts
                await self._check_metric_alerts(metric, data)
                
            except Exception as e:
                self.logger.error(f"Error monitoring {metric}: {str(e)}")
            
            await asyncio.sleep(interval)

    # Wallet Management Endpoints
    async def get_wallet(self, request: web.Request) -> web.Response:
        """Get wallet details"""
        address = request.match_info['address']
        try:
            wallet_details = await self.db_manager.get_wallet_details(address)
            if wallet_details:
                return web.json_response(wallet_details)
            return web.json_response({'error': 'Wallet not found'}, status=404)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def create_wallet(self, request: web.Request) -> web.Response:
        """Create a new wallet"""
        try:
            data = await request.json()
            new_wallet = await self.wallet_manager.create_wallet(data)
            await self.db_manager.add_wallet(new_wallet)
            return web.json_response(new_wallet)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def update_wallet(self, request: web.Request) -> web.Response:
        """Update wallet details"""
        address = request.match_info['address']
        try:
            data = await request.json()
            success = await self.db_manager.update_wallet_balance(address, data.get('balance', 0))
            if success:
                return web.json_response({'status': 'updated'})
            return web.json_response({'error': 'Update failed'}, status=400)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def get_wallet_balance(self, request: web.Request) -> web.Response:
        """Get wallet balance"""
        address = request.match_info['address']
        try:
            wallet = await self.db_manager.get_wallet_details(address)
            if wallet:
                return web.json_response({'balance': wallet['balance']})
            return web.json_response({'error': 'Wallet not found'}, status=404)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    # Transaction Management Endpoints
    async def create_transaction(self, request: web.Request) -> web.Response:
        """Create a new transaction"""
        try:
            tx_data = await request.json()
            success = await self.db_manager.add_transaction(tx_data)
            if success:
                return web.json_response({'status': 'created', 'tx_hash': tx_data['tx_hash']})
            return web.json_response({'error': 'Transaction creation failed'}, status=400)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def get_transaction(self, request: web.Request) -> web.Response:
        """Get transaction details"""
        tx_hash = request.match_info['tx_hash']
        try:
            tx = await self.db_manager.get_transactions(tx_hash, limit=1)
            if tx:
                return web.json_response(tx[0])
            return web.json_response({'error': 'Transaction not found'}, status=404)
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def get_pending_transactions(self, request: web.Request) -> web.Response:
        """Get list of pending transactions"""
        try:
            pending_tx = await self.db_manager.get_transactions(status='pending')
            return web.json_response({'pending_transactions': pending_tx})
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    # Database Management Endpoints
    async def get_db_mining_stats(self, request: web.Request) -> web.Response:
        """Get mining statistics from database"""
        try:
            time_range = request.query.get('range', '24h')
            stats = await self.db_manager.get_mining_stats(time_range)
            return web.json_response({'mining_stats': stats})
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def get_all_wallets(self, request: web.Request) -> web.Response:
        """Get all wallets from database"""
        try:
            wallets = await self.db_manager.get_wallet_details('all')
            return web.json_response({'wallets': wallets})
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def get_all_transactions(self, request: web.Request) -> web.Response:
        """Get all transactions from database"""
        try:
            limit = int(request.query.get('limit', 100))
            transactions = await self.db_manager.get_transactions('all', limit)
            return web.json_response({'transactions': transactions})
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)

    async def run(self):
        """Run the verification server with monitoring"""
        self.logger.info(f"Starting Mining Verification Server on {self.host}:{self.port}")
        
        # Initialize database
        await self.db_manager.init_database()
        
        # Start monitoring tasks
        await self._start_monitoring_tasks()
        
        # Run the server
        await web._run_app(self.app, host=self.host, port=self.port)

if __name__ == "__main__":
    server = MiningVerificationServer()
    server.run()
