
import paramiko
import socket
from django.conf import settings
from .models import ClientConnection, ConnectionLog
from .radius_server import RADIUSClient
import logging

logger = logging.getLogger(__name__)

class NetworkService:
    def __init__(self):
        self.routers = getattr(settings, 'MIKROTIK_ROUTERS', [])
    
    def connect_to_router(self, router_config):
        """Connect to MikroTik router via SSH"""
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            ssh.connect(
                hostname=router_config['host'],
                username=router_config['username'],
                password=router_config['password'],
                port=22,  # SSH port
                timeout=10
            )
            
            return ssh
        except Exception as e:
            logger.error(f"Failed to connect to router {router_config['host']}: {str(e)}")
            return None
    
    def execute_command(self, ssh, command):
        """Execute command on MikroTik router"""
        try:
            stdin, stdout, stderr = ssh.exec_command(command)
            output = stdout.read().decode('utf-8')
            error = stderr.read().decode('utf-8')
            
            if error:
                logger.error(f"Command error: {error}")
                return None
            
            return output
        except Exception as e:
            logger.error(f"Failed to execute command: {str(e)}")
            return None
    
    def disable_pppoe_user(self, username):
        """Disable PPPoE user on MikroTik"""
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Disable PPPoE secret
                    command = f'/ppp secret set [find name="{username}"] disabled=yes'
                    result = self.execute_command(ssh, command)
                    
                    # Disconnect active session
                    command = f'/ppp active remove [find name="{username}"]'
                    self.execute_command(ssh, command)
                    
                    logger.info(f"Disabled PPPoE user: {username}")
                    
                    # Log the action
                    try:
                        connection = ClientConnection.objects.get(username=username)
                        connection.is_active = False
                        connection.save()
                        
                        ConnectionLog.objects.create(
                            connection=connection,
                            action='suspend',
                            details=f'Suspended due to overdue payment'
                        )
                    except ClientConnection.DoesNotExist:
                        pass
                    
                except Exception as e:
                    logger.error(f"Failed to disable user {username}: {str(e)}")
                finally:
                    ssh.close()
    
    def enable_pppoe_user(self, username):
        """Enable PPPoE user on MikroTik"""
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Enable PPPoE secret
                    command = f'/ppp secret set [find name="{username}"] disabled=no'
                    result = self.execute_command(ssh, command)
                    
                    logger.info(f"Enabled PPPoE user: {username}")
                    
                    # Log the action
                    try:
                        connection = ClientConnection.objects.get(username=username)
                        connection.is_active = True
                        connection.save()
                        
                        ConnectionLog.objects.create(
                            connection=connection,
                            action='reactivate',
                            details=f'Reactivated after payment'
                        )
                    except ClientConnection.DoesNotExist:
                        pass
                    
                except Exception as e:
                    logger.error(f"Failed to enable user {username}: {str(e)}")
                finally:
                    ssh.close()
    
    def create_pppoe_user(self, username, password, profile='default'):
        """Create new PPPoE user on MikroTik"""
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Create PPPoE secret
                    command = f'/ppp secret add name="{username}" password="{password}" profile="{profile}"'
                    result = self.execute_command(ssh, command)
                    
                    logger.info(f"Created PPPoE user: {username}")
                    
                except Exception as e:
                    logger.error(f"Failed to create user {username}: {str(e)}")
                finally:
                    ssh.close()
    
    def get_active_sessions(self):
        """Get list of active PPPoE sessions"""
        active_sessions = []
        
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    command = '/ppp active print'
                    result = self.execute_command(ssh, command)
                    
                    if result:
                        # Parse the output (this is simplified, you might need to adjust based on actual output format)
                        lines = result.strip().split('\n')
                        for line in lines[1:]:  # Skip header
                            if line.strip():
                                parts = line.split()
                                if len(parts) >= 4:
                                    session_info = {
                                        'username': parts[1],
                                        'address': parts[2] if len(parts) > 2 else '',
                                        'uptime': parts[3] if len(parts) > 3 else '',
                                    }
                                    active_sessions.append(session_info)
                    
                except Exception as e:
                    logger.error(f"Failed to get active sessions: {str(e)}")
                finally:
                    ssh.close()
        
        return active_sessions
    
    def suspend_customer(self, customer):
        """Suspend customer's internet access"""
        connections = ClientConnection.objects.filter(customer=customer, is_active=True)
        
        for connection in connections:
            self.disable_pppoe_user(connection.username)
    
    def reactivate_customer(self, customer):
        """Reactivate customer's internet access"""
        connections = ClientConnection.objects.filter(customer=customer)
        
        for connection in connections:
            self.enable_pppoe_user(connection.username)
    
    def sync_connection_status(self):
        """Sync connection status with MikroTik routers"""
        active_sessions = self.get_active_sessions()
        active_usernames = [session['username'] for session in active_sessions]
        
        # Update online status
        ClientConnection.objects.all().update(is_online=False)
        
        for session in active_sessions:
            try:
                connection = ClientConnection.objects.get(username=session['username'])
                connection.is_online = True
                connection.ip_address = session.get('address', '')
                connection.save()
            except ClientConnection.DoesNotExist:
                pass
        
        logger.info(f"Synced status for {len(active_sessions)} active sessions")
    
    def capture_customer_first_connection(self, username):
        """Capture MAC address and set installation date for first-time connection"""
        from customers.models import Customer
        from django.utils import timezone
        
        try:
            connection = ClientConnection.objects.get(username=username)
            customer = connection.customer
            
            # Only update if this is the first connection (no router_mac set)
            if not customer.router_mac:
                # Get MAC address from MikroTik
                mac_address = self.get_client_mac_address(username)
                if mac_address:
                    customer.router_mac = mac_address
                    customer.installation_date = timezone.now()
                    customer.save()
                    
                    logger.info(f"Captured first connection data for {customer.full_name}: MAC {mac_address}")
                    
                    # Log the event
                    ConnectionLog.objects.create(
                        connection=connection,
                        action='first_connection',
                        details=f'First connection captured - MAC: {mac_address}'
                    )
                    
        except ClientConnection.DoesNotExist:
            logger.error(f"Connection not found for username: {username}")
    
    def get_client_mac_address(self, username):
        """Get MAC address for a specific client from MikroTik"""
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Get MAC address from active session
                    command = f'/ppp active print where name="{username}"'
                    result = self.execute_command(ssh, command)
                    
                    if result:
                        # Parse MAC address from output
                        lines = result.strip().split('\n')
                        for line in lines:
                            if 'calling-station-id' in line:
                                # Extract MAC address (format may vary)
                                parts = line.split('=')
                                if len(parts) > 1:
                                    mac = parts[1].strip().strip('"')
                                    return mac
                    
                except Exception as e:
                    logger.error(f"Failed to get MAC address for {username}: {str(e)}")
                finally:
                    ssh.close()
        
        return None
    
    def get_customers_by_tag(self, tag_name):
        """Get all customers with a specific tag"""
        from customers.models import Customer, CustomerTag
        
        try:
            tag = CustomerTag.objects.get(name=tag_name)
            return Customer.objects.filter(tags=tag, is_active=True)
        except CustomerTag.DoesNotExist:
            logger.error(f"Tag '{tag_name}' not found")
            return Customer.objects.none()
    
    def send_notification_to_tag(self, tag_name, message, notification_type='downtime'):
        """Send notifications to all customers with a specific tag"""
        customers = self.get_customers_by_tag(tag_name)
        
        # Here you would implement your notification logic
        # This could be SMS, email, or push notifications
        for customer in customers:
            # Example: Send SMS
            self.send_sms_notification(customer.phone, message)
            
            logger.info(f"Sent {notification_type} notification to {customer.full_name} (Tag: {tag_name})")
    
    def send_sms_notification(self, phone_number, message):
        """Send SMS notification (implement with your SMS provider)"""
        # Placeholder for SMS implementation
        # You would integrate with your SMS service provider here
        logger.info(f"SMS sent to {phone_number}: {message}")
    
    def configure_mikrotik_radius(self, radius_server_ip, radius_secret):
        """Configure MikroTik routers to use external RADIUS server"""
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Add RADIUS server configuration
                    commands = [
                        f'/radius add service=ppp address={radius_server_ip} secret="{radius_secret}"',
                        '/ppp aaa set use-radius=yes',
                        '/ppp aaa set accounting=yes',
                    ]
                    
                    for command in commands:
                        result = self.execute_command(ssh, command)
                        logger.info(f"RADIUS config command executed: {command}")
                    
                    logger.info(f"RADIUS configured on router {router_config['host']}")
                    
                except Exception as e:
                    logger.error(f"Failed to configure RADIUS on {router_config['host']}: {str(e)}")
                finally:
                    ssh.close()
    
    def test_radius_connectivity(self, username, password):
        """Test RADIUS authentication"""
        radius_settings = getattr(settings, 'RADIUS_SERVER', {})
        if not radius_settings:
            logger.error("No RADIUS server configured")
            return False
            
        client = RADIUSClient(
            radius_settings.get('HOST'),
            radius_settings.get('PORT', 1812),
            radius_settings.get('SECRET')
        )
        
        return client.authenticate(username, password)
    
    def sync_users_to_radius(self):
        """Sync active connections to RADIUS server database"""
        active_connections = ClientConnection.objects.filter(is_active=True)
        
        for connection in active_connections:
            # This would sync user data to your RADIUS database
            # Implementation depends on your RADIUS server type
            logger.info(f"Syncing user {connection.username} to RADIUS")
    
    def configure_router_for_radius_auth(self, router_config, radius_ip, radius_secret):
        """Configure a specific router for RADIUS authentication"""
        ssh = self.connect_to_router(router_config)
        if ssh:
            try:
                commands = [
                    # Configure RADIUS server
                    f'/radius add service=ppp address={radius_ip} secret="{radius_secret}" timeout=3s',
                    
                    # Enable RADIUS for PPP
                    '/ppp aaa set use-radius=yes',
                    '/ppp aaa set accounting=yes',
                    
                    # Optional: Set interim accounting interval
                    '/ppp aaa set interim-update=5m',
                ]
                
                for command in commands:
                    result = self.execute_command(ssh, command)
                    if result is not None:
                        logger.info(f"Executed: {command}")
                
                logger.info(f"Router {router_config['host']} configured for RADIUS")
                return True
                
            except Exception as e:
                logger.error(f"Failed to configure RADIUS on {router_config['host']}: {str(e)}")
                return False
            finally:
                ssh.close()
        
        return False
    
    def get_radius_accounting_data(self):
        """Retrieve accounting data from RADIUS logs"""
        # This would parse RADIUS accounting logs or database
        # to get usage statistics for billing
        accounting_data = []
        
        for router_config in self.routers:
            ssh = self.connect_to_router(router_config)
            if ssh:
                try:
                    # Get PPP active sessions with accounting info
                    command = '/ppp active print detail'
                    result = self.execute_command(ssh, command)
                    
                    if result:
                        # Parse accounting data (simplified)
                        lines = result.strip().split('\n')
                        for line in lines:
                            if 'name=' in line and 'bytes-in=' in line:
                                # Extract usage data
                                user_data = self.parse_ppp_session_data(line)
                                if user_data:
                                    accounting_data.append(user_data)
                    
                except Exception as e:
                    logger.error(f"Failed to get accounting data from {router_config['host']}: {str(e)}")
                finally:
                    ssh.close()
        
        return accounting_data
    
    def parse_ppp_session_data(self, session_line):
        """Parse PPP session data for accounting"""
        try:
            data = {}
            parts = session_line.split()
            
            for part in parts:
                if '=' in part:
                    key, value = part.split('=', 1)
                    data[key] = value
            
            return {
                'username': data.get('name', ''),
                'bytes_in': int(data.get('bytes-in', 0)),
                'bytes_out': int(data.get('bytes-out', 0)),
                'uptime': data.get('uptime', ''),
                'ip_address': data.get('address', ''),
            }
        except Exception as e:
            logger.error(f"Failed to parse session data: {e}")
            return None
