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

class ClientState:
    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

    def process_command(self, client):
        """Process commands from the queue."""
        if not self.command_queue.empty():
            print(f"Client {self.client_id} processing command queue, size: {self.command_queue.qsize()}")
            command = self.command_queue.get()
            if command == "handshake":
                try:
                    print(f"Client {self.client_id} starting handshake, initiator: {self.initiator}")
                    self.session = NoiseXKSession(self.keypair, self.peer_pubkey)
                    self.session.handshake(client.sock, self.initiator)
                    print(f"Client {self.client_id} handshake complete")
                    client.send("HANDSHAKE_DONE")
                except Exception as e:
                    print(f"Client {self.client_id} handshake failed: {e}")
                    client.state_changed.emit("CALL_END", "", self.client_id)
                finally:
                    self.handshake_in_progress = False
                    self.handshake_start_time = None

    def start_handshake(self, initiator, keypair, peer_pubkey):
        """Queue handshake command."""
        self.initiator = initiator
        self.keypair = keypair
        self.peer_pubkey = peer_pubkey
        print(f"Client {self.client_id} 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:
            decoded_data = data.decode('utf-8').strip()
            print(f"Client {self.client_id} received raw: {decoded_data}")
            if decoded_data in ["RINGING", "CALL_END", "CALL_DROPPED", "IN_CALL", "HANDSHAKE", "HANDSHAKE_DONE"]:
                client.state_changed.emit(decoded_data, decoded_data, self.client_id)
                if decoded_data == "HANDSHAKE":
                    self.handshake_in_progress = True
                elif decoded_data == "HANDSHAKE_DONE":
                    self.call_active = True
            else:
                print(f"Client {self.client_id} ignored unexpected text message: {decoded_data}")
        except UnicodeDecodeError:
            if self.call_active and self.session:
                try:
                    print(f"Client {self.client_id} received audio packet, length={len(data)}")
                    decrypted_data = self.session.decrypt(data)
                    print(f"Client {self.client_id} decrypted audio packet, length={len(decrypted_data)}")
                    client.data_received.emit(decrypted_data, self.client_id)
                except Exception as e:
                    print(f"Client {self.client_id} failed to process audio packet: {e}")
            else:
                print(f"Client {self.client_id} ignored non-text message: {data.hex()}")

    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:
                print(f"Client {self.client_id} handshake timeout after 30s")
                client.state_changed.emit("CALL_END", "", self.client_id)
                self.handshake_in_progress = False
                self.handshake_start_time = None