"""
Network Monitoring Module
Checks server connectivity and manages WiFi restart on connection failure
"""

import subprocess
import time
import random
import requests
from datetime import datetime
from kivy.logger import Logger
from kivy.clock import Clock


class NetworkMonitor:
    """Monitor network connectivity and manage WiFi restart"""
    
    def __init__(self, server_url, check_interval_min=30, check_interval_max=45, wifi_restart_duration=20):
        """
        Initialize network monitor
        
        Args:
            server_url (str): Server URL to check connectivity (e.g., 'https://digi-signage.moto-adv.com')
            check_interval_min (int): Minimum minutes between checks (default: 30)
            check_interval_max (int): Maximum minutes between checks (default: 45)
            wifi_restart_duration (int): Minutes to keep WiFi off during restart (default: 20)
        """
        self.server_url = server_url.rstrip('/')
        self.check_interval_min = check_interval_min * 60  # Convert to seconds
        self.check_interval_max = check_interval_max * 60  # Convert to seconds
        self.wifi_restart_duration = wifi_restart_duration * 60  # Convert to seconds
        self.is_monitoring = False
        self.scheduled_event = None
        self.consecutive_failures = 0
        self.max_failures_before_restart = 3  # Restart WiFi after 3 consecutive failures
        
    def start_monitoring(self):
        """Start the network monitoring loop"""
        if not self.is_monitoring:
            self.is_monitoring = True
            Logger.info("NetworkMonitor: Starting network monitoring")
            self._schedule_next_check()
    
    def stop_monitoring(self):
        """Stop the network monitoring"""
        self.is_monitoring = False
        if self.scheduled_event:
            self.scheduled_event.cancel()
            self.scheduled_event = None
        Logger.info("NetworkMonitor: Stopped network monitoring")
    
    def _schedule_next_check(self):
        """Schedule the next connectivity check at a random interval"""
        if not self.is_monitoring:
            return
        
        # Random interval between min and max
        next_check_seconds = random.randint(self.check_interval_min, self.check_interval_max)
        next_check_minutes = next_check_seconds / 60
        
        Logger.info(f"NetworkMonitor: Next check scheduled in {next_check_minutes:.1f} minutes")
        
        # Schedule using Kivy Clock
        self.scheduled_event = Clock.schedule_once(
            lambda dt: self._check_connectivity(), 
            next_check_seconds
        )
    
    def _check_connectivity(self):
        """Check network connectivity to server"""
        Logger.info("NetworkMonitor: Checking server connectivity...")
        
        if self._test_server_connection():
            Logger.info("NetworkMonitor: ✓ Server connection successful")
            self.consecutive_failures = 0
        else:
            self.consecutive_failures += 1
            Logger.warning(f"NetworkMonitor: ✗ Server connection failed (attempt {self.consecutive_failures}/{self.max_failures_before_restart})")
            
            if self.consecutive_failures >= self.max_failures_before_restart:
                Logger.error("NetworkMonitor: Multiple connection failures detected - initiating WiFi restart")
                self._restart_wifi()
                self.consecutive_failures = 0  # Reset counter after restart
        
        # Schedule next check
        self._schedule_next_check()
    
    def _test_server_connection(self):
        """
        Test connection to the server using ping only
        This works in closed networks where the server is local
        
        Returns:
            bool: True if server is reachable, False otherwise
        """
        try:
            # Extract hostname from server URL (remove http:// or https://)
            hostname = self.server_url.replace('https://', '').replace('http://', '').split('/')[0]
            
            Logger.info(f"NetworkMonitor: Pinging server: {hostname}")
            
            # Ping the server hostname with 3 attempts
            result = subprocess.run(
                ['ping', '-c', '3', '-W', '3', hostname],
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                Logger.info(f"NetworkMonitor: ✓ Server {hostname} is reachable")
                return True
            else:
                Logger.warning(f"NetworkMonitor: ✗ Cannot reach server {hostname}")
                return False
                
        except subprocess.TimeoutExpired:
            Logger.warning(f"NetworkMonitor: ✗ Ping timeout to server")
            return False
        except Exception as e:
            Logger.error(f"NetworkMonitor: Error pinging server: {e}")
            return False
    
    def _restart_wifi(self):
        """
        Restart WiFi by turning it off for a specified duration then back on
        This runs in a separate thread to not block the main application
        """
        def wifi_restart_thread():
            try:
                Logger.info("NetworkMonitor: ====================================")
                Logger.info("NetworkMonitor: INITIATING WIFI RESTART SEQUENCE")
                Logger.info("NetworkMonitor: ====================================")
                
                # Turn off WiFi using rfkill (more reliable on Raspberry Pi)
                Logger.info("NetworkMonitor: Turning WiFi OFF using rfkill...")
                result = subprocess.run(
                    ['sudo', 'rfkill', 'block', 'wifi'],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                
                if result.returncode == 0:
                    Logger.info("NetworkMonitor: ✓ WiFi turned OFF successfully (rfkill)")
                    Logger.info("NetworkMonitor: WiFi is now DISABLED and will remain OFF")
                else:
                    Logger.error(f"NetworkMonitor: rfkill failed, trying ifconfig...")
                    Logger.error(f"NetworkMonitor: rfkill error: {result.stderr}")
                    
                    # Fallback to ifconfig
                    result2 = subprocess.run(
                        ['sudo', 'ifconfig', 'wlan0', 'down'],
                        capture_output=True,
                        text=True,
                        timeout=10
                    )
                    
                    if result2.returncode == 0:
                        Logger.info("NetworkMonitor: ✓ WiFi turned OFF successfully (ifconfig)")
                    else:
                        Logger.error(f"NetworkMonitor: Failed to turn WiFi off: {result2.stderr}")
                        Logger.error(f"NetworkMonitor: Return code: {result2.returncode}")
                        Logger.error(f"NetworkMonitor: STDOUT: {result2.stdout}")
                        return
                
                # Wait for the specified duration with WiFi OFF
                wait_minutes = self.wifi_restart_duration / 60
                Logger.info(f"NetworkMonitor: ====================================")
                Logger.info(f"NetworkMonitor: WiFi will remain OFF for {wait_minutes:.0f} minutes")
                Logger.info(f"NetworkMonitor: Waiting period started at: {datetime.now().strftime('%H:%M:%S')}")
                Logger.info(f"NetworkMonitor: ====================================")
                
                # Sleep while WiFi is OFF
                time.sleep(self.wifi_restart_duration)
                
                Logger.info(f"NetworkMonitor: Wait period completed at: {datetime.now().strftime('%H:%M:%S')}")
                
                # Turn WiFi back on after the wait period
                Logger.info("NetworkMonitor: ====================================")
                Logger.info("NetworkMonitor: Now turning WiFi back ON...")
                Logger.info("NetworkMonitor: ====================================")
                
                # Unblock WiFi using rfkill
                result = subprocess.run(
                    ['sudo', 'rfkill', 'unblock', 'wifi'],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                
                if result.returncode == 0:
                    Logger.info("NetworkMonitor: ✓ WiFi unblocked successfully (rfkill)")
                else:
                    Logger.error(f"NetworkMonitor: rfkill unblock failed: {result.stderr}")
                
                # Also bring interface up
                result2 = subprocess.run(
                    ['sudo', 'ifconfig', 'wlan0', 'up'],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                
                if result2.returncode == 0:
                    Logger.info("NetworkMonitor: ✓ WiFi interface brought UP successfully")
                    
                    # Wait a bit for connection to establish
                    Logger.info("NetworkMonitor: Waiting 10 seconds for WiFi to initialize...")
                    time.sleep(10)
                    
                    # Try to restart DHCP
                    Logger.info("NetworkMonitor: Requesting IP address...")
                    subprocess.run(
                        ['sudo', 'dhclient', 'wlan0'],
                        capture_output=True,
                        text=True,
                        timeout=15
                    )
                    
                    Logger.info("NetworkMonitor: ====================================")
                    Logger.info("NetworkMonitor: WIFI RESTART SEQUENCE COMPLETED")
                    Logger.info("NetworkMonitor: ====================================")
                else:
                    Logger.error(f"NetworkMonitor: Failed to turn WiFi on: {result.stderr}")
                    
            except subprocess.TimeoutExpired:
                Logger.error("NetworkMonitor: WiFi restart command timeout")
            except Exception as e:
                Logger.error(f"NetworkMonitor: Error during WiFi restart: {e}")
        
        # Run in separate thread to not block the application
        import threading
        thread = threading.Thread(target=wifi_restart_thread, daemon=True)
        thread.start()
