<?php
/**
 * WebSocket Client
 * 
 * This class provides methods to connect to and send messages via WebSocket
 */

namespace Services\Core\WebSocket;

class WebSocketClient {
    private $host;
    private $port;
    private $path;
    private $socket;
    
    /**
     * Constructor
     * 
     * @param string $host WebSocket host (default: localhost)
     * @param int $port WebSocket port (default: 8080)
     * @param string $path WebSocket path (default: /)
     */
    public function __construct($host = 'localhost', $port = 8080, $path = '/') {
        $this->host = $host;
        $this->port = $port;
        $this->path = $path;
    }
    
    /**
     * Connect to WebSocket server
     * 
     * @return bool Success status
     */
    public function connect() {
        $address = "tcp://{$this->host}:{$this->port}";
        
        // Create socket
        $this->socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if ($this->socket === false) {
            $errorCode = socket_last_error();
            $errorMessage = socket_strerror($errorCode);
            error_log("WebSocket connection error: [$errorCode] $errorMessage");
            return false;
        }
        
        // Connect socket
        $result = @socket_connect($this->socket, $this->host, $this->port);
        if ($result === false) {
            $errorCode = socket_last_error($this->socket);
            $errorMessage = socket_strerror($errorCode);
            error_log("WebSocket connection error: [$errorCode] $errorMessage");
            socket_close($this->socket);
            return false;
        }
        
        // WebSocket handshake
        $key = base64_encode(openssl_random_pseudo_bytes(16));
        $headers = "GET {$this->path} HTTP/1.1\r\n";
        $headers .= "Host: {$this->host}:{$this->port}\r\n";
        $headers .= "Upgrade: websocket\r\n";
        $headers .= "Connection: Upgrade\r\n";
        $headers .= "Sec-WebSocket-Key: $key\r\n";
        $headers .= "Sec-WebSocket-Version: 13\r\n\r\n";
        
        // Send headers
        socket_write($this->socket, $headers, strlen($headers));
        
        // Read response
        $response = socket_read($this->socket, 2048);
        
        // Check if handshake is successful
        if (strpos($response, '101 Switching Protocols') === false) {
            error_log("WebSocket handshake failed: $response");
            socket_close($this->socket);
            return false;
        }
        
        return true;
    }
    
    /**
     * Send message to WebSocket server
     * 
     * @param string $message Message to send
     * @return bool Success status
     */
    public function send($message) {
        try {
            // Try to connect if not already connected
            if (!$this->socket) {
                if (!$this->connect()) {
                    return false;
                }
            }
            
            // Frame the message according to WebSocket protocol
            $header = chr(0x81); // Text frame (FIN + opcode)
            $length = strlen($message);
            
            if ($length <= 125) {
                $header .= chr($length);
            } elseif ($length <= 65535) {
                $header .= chr(126) . chr($length >> 8) . chr($length & 0xFF);
            } else {
                $header .= chr(127) . pack('N', 0) . pack('N', $length);
            }
            
            // Send frame
            $frame = $header . $message;
            $sent = socket_write($this->socket, $frame, strlen($frame));
            
            return $sent !== false;
        } catch (\Exception $e) {
            error_log('WebSocket send error: ' . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Close WebSocket connection
     * 
     * @return bool Success status
     */
    public function close() {
        if ($this->socket) {
            // Send close frame
            $closeFrame = chr(0x88) . chr(0);
            socket_write($this->socket, $closeFrame, strlen($closeFrame));
            
            // Close socket
            socket_close($this->socket);
            $this->socket = null;
            
            return true;
        }
        
        return false;
    }
    
    /**
     * Destructor - automatically close connection
     */
    public function __destruct() {
        $this->close();
    }
}
