# protocol_client_state.py
from queue import Queue
from session import NoiseXKSession
import time

class ProtocolClientState:
    """Enhanced client state for integrated protocol with voice codec"""
    
    def __init__(self, client_id):
        self.client_id = client_id
        self.command_queue = Queue()
        self.initiator = None
        self.keypair = None
        self.peer_pubkey = None
        self.session = None
        self.handshake_in_progress = False
        self.handshake_start_time = None
        self.call_active = False
        self.voice_active = False
        self.debug_callback = None
    
    def debug(self, message):
        """Send debug message"""
        if self.debug_callback:
            self.debug_callback(f"[State{self.client_id+1}] {message}")
        else:
            print(f"[State{self.client_id+1}] {message}")
        
    def process_command(self, client):
        """Process commands from the queue."""
        if not self.command_queue.empty():
            self.debug(f"Processing command queue, size: {self.command_queue.qsize()}")
            command = self.command_queue.get()
            self.debug(f"Processing command: {command}")
            
            if command == "handshake":
                # Handshake is now handled by the wrapper in the client
                self.debug(f"Handshake command processed")
                self.handshake_in_progress = False
                self.handshake_start_time = None
                    
            elif command == "start_voice":
                if client.handshake_complete:
                    client.start_voice_session()
                    self.voice_active = True
                    
            elif command == "end_voice":
                if self.voice_active:
                    client.end_voice_session()
                    self.voice_active = False
    
    def start_handshake(self, initiator, keypair, peer_pubkey):
        """Queue handshake command."""
        self.initiator = initiator
        self.keypair = keypair
        self.peer_pubkey = peer_pubkey
        self.debug(f"Queuing handshake, initiator: {initiator}")
        self.handshake_in_progress = True
        self.handshake_start_time = time.time()
        self.command_queue.put("handshake")
    
    def handle_data(self, client, data):
        """Handle received data (control or audio)."""
        try:
            # Try to decode as text first
            decoded_data = data.decode('utf-8').strip()
            self.debug(f"Received raw: {decoded_data}")
            
            # Handle control messages
            if decoded_data in ["RINGING", "CALL_END", "CALL_DROPPED", "IN_CALL", "HANDSHAKE", "HANDSHAKE_DONE"]:
                self.debug(f"Emitting state change: {decoded_data}")
                # Log which client is receiving what
                self.debug(f"Client {self.client_id} received {decoded_data} message")
                client.state_changed.emit(decoded_data, decoded_data, self.client_id)
                
                if decoded_data == "IN_CALL":
                    self.debug(f"Received IN_CALL, setting call_active = True")
                    self.call_active = True
                elif decoded_data == "HANDSHAKE":
                    self.debug(f"Received HANDSHAKE, setting handshake_in_progress = True")
                    self.handshake_in_progress = True
                elif decoded_data == "HANDSHAKE_DONE":
                    self.debug(f"Received HANDSHAKE_DONE from peer")
                    self.call_active = True
                    # Start voice session on this side too
                    if client.handshake_complete and not client.voice_active:
                        self.debug(f"Starting voice session after receiving HANDSHAKE_DONE")
                        self.command_queue.put("start_voice")
                elif decoded_data in ["CALL_END", "CALL_DROPPED"]:
                    self.debug(f"Received {decoded_data}, ending call")
                    self.call_active = False
                    if self.voice_active:
                        self.command_queue.put("end_voice")
            else:
                self.debug(f"Ignored unexpected text message: {decoded_data}")
                
        except UnicodeDecodeError:
            # Handle binary data (protocol messages or encrypted data)
            if len(data) > 0 and data[0] == 0x20 and not client.handshake_complete:  # Noise handshake message only before handshake completes
                self.debug(f"Received Noise handshake message")
                # Initialize responder if not already done
                if not client.handshake_initiated:
                    # Find the other phone's public key
                    # This is a bit hacky but works for our 2-phone setup
                    manager = getattr(client, 'manager', None)
                    if manager:
                        other_phone = manager.phones[1 - self.client_id]
                        client.start_handshake(initiator=False, 
                                             keypair=client.keypair or manager.phones[self.client_id]['keypair'],
                                             peer_pubkey=other_phone['public_key'])
                # Pass to protocol handler
                client._handle_protocol_message(data)
            elif client.handshake_complete and client.noise_wrapper:
                # Pass encrypted data back to client for decryption
                client._handle_encrypted_data(data)
            else:
                # Pass other binary messages to protocol handler only if not yet complete
                if not client.handshake_complete:
                    client._handle_protocol_message(data)
    
    def check_handshake_timeout(self, client):
        """Check for handshake timeout."""
        if self.handshake_in_progress and self.handshake_start_time:
            if time.time() - self.handshake_start_time > 30:
                self.debug(f"Handshake timeout after 30s")
                client.state_changed.emit("CALL_END", "", self.client_id)
                self.handshake_in_progress = False
                self.handshake_start_time = None
                
    def queue_voice_command(self, command):
        """Queue voice-related commands"""
        if command in ["start_voice", "end_voice"]:
            self.command_queue.put(command)