import threading
import time
from datetime import datetime, timedelta

class TransmissionController:
    """Handles transmission cycle logic and state management"""
    
    def __init__(self, gpio_controller, data_logger, status_callback=None):
        self.gpio_controller = gpio_controller
        self.data_logger = data_logger
        self.status_callback = status_callback or (lambda msg: print(f"[TX] {msg}"))
        
        # Transmission state
        self.cycle_state = 'idle'  # 'idle', 'transmitting', 'pausing'
        self.cycle_timer = None
        self.cycle_thread = None
        
        # Timing settings
        self.transmit_time = 60  # seconds
        self.pause_time = 30     # seconds
        
        # Current frequency
        self.current_frequency = 1.0
        
        # GUI callbacks
        self.gui_callbacks = {}
        
        # Threading lock and control
        self.state_lock = threading.Lock()
        self.cycle_running = False
        
        # Precision timing variables
        self.cycle_start_time = None
        self.cycle_number = 0
    
    def set_timing_parameters(self, transmit_time, pause_time):
        """Set transmit and pause times"""
        with self.state_lock:
            self.transmit_time = transmit_time
            self.pause_time = pause_time
        self.status_callback(f"Timing updated: {transmit_time}s TX, {pause_time}s pause")
    
    def set_frequency(self, frequency):
        """Set transmission frequency"""
        with self.state_lock:
            self.current_frequency = frequency
    
    def register_gui_callbacks(self, callbacks):
        """Register GUI update callbacks"""
        self.gui_callbacks = callbacks
    
    def start_transmission_cycle(self):
        """Start the transmit/pause cycle with precision timing"""
        with self.state_lock:
            if self.cycle_state != 'idle':
                self.status_callback("Transmission cycle already active")
                return False
                
            self.status_callback(f"Starting transmission cycle: {self.transmit_time}s ON, {self.pause_time}s OFF")
            self.cycle_state = 'transmitting'
            self.cycle_running = True
            self.cycle_start_time = datetime.utcnow()
            self.cycle_number = 0
        
        # Start the precision timing thread instead of simple timers
        self.cycle_thread = threading.Thread(target=self._precision_cycle_loop, daemon=True)
        self.cycle_thread.start()
        
        # Start first transmission immediately
        self._start_gpio_transmission()
        
        # Log transmission start
        if self.data_logger.is_logging_active():
            self.data_logger.log_transmission_start(self.current_frequency)
        
        return True
    
    def stop_transmission_cycle(self):
        """Stop the transmission cycle"""
        with self.state_lock:
            was_active = self.cycle_state != 'idle'
            self.cycle_state = 'idle'
            self.cycle_running = False
        
        # Cancel any pending timer
        if self.cycle_timer:
            self.cycle_timer.cancel()
            self.cycle_timer = None
        
        # Wait for cycle thread to finish
        if self.cycle_thread and self.cycle_thread.is_alive():
            self.cycle_thread.join(timeout=1.0)
        
        # Stop GPIO transmission
        self._stop_gpio_transmission()
        
        # Log manual stop if it was active
        if was_active and self.data_logger.is_logging_active():
            self.data_logger.log_manual_stop()
        
        self.status_callback("Transmission cycle stopped")
        return True
    
    def get_cycle_state(self):
        """Get current cycle state"""
        with self.state_lock:
            return self.cycle_state
    
    def is_active(self):
        """Check if transmission cycle is active"""
        with self.state_lock:
            return self.cycle_state != 'idle'
    
    def _precision_cycle_loop(self):
        """Precision timing loop that maintains exact timing without drift"""
        total_cycle_time = self.transmit_time + self.pause_time
        
        while self.cycle_running:
            current_time = datetime.utcnow()
            
            # Calculate elapsed time since cycle start
            elapsed_total = (current_time - self.cycle_start_time).total_seconds()
            
            # Calculate where we should be in the current cycle
            current_cycle = int(elapsed_total // total_cycle_time)
            time_in_cycle = elapsed_total % total_cycle_time
            
            # Check if we've moved to a new cycle
            if current_cycle > self.cycle_number:
                self.cycle_number = current_cycle
                
            # Determine what state we should be in
            if time_in_cycle < self.transmit_time:
                # Should be transmitting
                target_state = 'transmitting'
            else:
                # Should be pausing
                target_state = 'pausing'
            
            # Update state if needed
            with self.state_lock:
                if self.cycle_state != target_state and self.cycle_running:
                    if target_state == 'pausing' and self.cycle_state == 'transmitting':
                        self._switch_to_pause()
                    elif target_state == 'transmitting' and self.cycle_state == 'pausing':
                        self._switch_to_transmit()
            
            # Calculate next transition time
            if target_state == 'transmitting':
                # Next transition is to pause
                next_transition = self.cycle_start_time + timedelta(
                    seconds=(current_cycle * total_cycle_time + self.transmit_time)
                )
            else:
                # Next transition is to transmit (start of next cycle)
                next_transition = self.cycle_start_time + timedelta(
                    seconds=((current_cycle + 1) * total_cycle_time)
                )
            
            # Sleep until near the next transition
            sleep_time = (next_transition - datetime.utcnow()).total_seconds()
            if sleep_time > 0.1:
                time.sleep(max(0.05, sleep_time - 0.05))  # Wake up 50ms early
            elif sleep_time > 0:
                time.sleep(sleep_time)
            
            # Precision wait for exact transition time
            while datetime.utcnow() < next_transition and self.cycle_running:
                time.sleep(0.001)  # 1ms precision wait
    
    def _switch_to_pause(self):
        """Switch from transmitting to pausing state"""
        self.cycle_state = 'pausing'
        self.status_callback(f"Starting pause cycle: {self.pause_time}s")
        
        # Log pause start
        if self.data_logger.is_logging_active():
            self.data_logger.log_pause_start(self.pause_time)
        
        # Stop GPIO transmission
        self._stop_gpio_transmission()
        
        # Update GUI status for pause - THIS WAS MISSING!
        if 'status_update' in self.gui_callbacks:
            self.gui_callbacks['status_update']("PAUSED", "orange")
    
    def _switch_to_transmit(self):
        """Switch from pausing to transmitting state"""
        self.cycle_state = 'transmitting'
        self.status_callback("Resuming transmission cycle")
        
        # Log pause completion
        if self.data_logger.is_logging_active():
            self.data_logger.log_pause_complete()
        
        # Start GPIO transmission
        self._start_gpio_transmission()
    
    def _start_gpio_transmission(self):
        """Start actual GPIO transmission"""
        # Set up indicator callbacks for GUI
        indicator_callbacks = {
            'onoff': self.gui_callbacks.get('onoff_indicator'),
            'duty': self.gui_callbacks.get('duty_indicator'), 
            'polarity': self.gui_callbacks.get('polarity_indicator')
        }
        
        # Start GPIO transmission
        self.gpio_controller.start_transmission(self.current_frequency, indicator_callbacks)
        
        # Update GUI status - Fixed to show TRANSMITTING properly
        if 'status_update' in self.gui_callbacks:
            self.gui_callbacks['status_update']("TRANSMITTING", "green")
    
    def _stop_gpio_transmission(self):
        """Stop GPIO transmission"""
        indicator_callbacks = {
            'onoff': self.gui_callbacks.get('onoff_indicator'),
            'duty': self.gui_callbacks.get('duty_indicator'),
            'polarity': self.gui_callbacks.get('polarity_indicator')
        }
        
        self.gpio_controller.stop_transmission(indicator_callbacks)
        
        # Don't update GUI status here - let the state machine handle it
        # This prevents "NOT TRANSMITTING" from showing during pause cycles
    
    def _start_pause_cycle(self):
        """Legacy method - kept for compatibility but not used with precision timing"""
        # This method is replaced by _switch_to_pause in the precision timing system
        pass
    
    def _resume_transmission_cycle(self):
        """Legacy method - kept for compatibility but not used with precision timing"""
        # This method is replaced by _switch_to_transmit in the precision timing system
        pass
    
    def cleanup(self):
        """Clean up transmission controller"""
        self.stop_transmission_cycle()
        self.status_callback("Transmission controller cleaned up")