<?php
require_once '../config/database.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

class WebSocketServer {
    private $clients = [];
    private $devices = [];
    
    public function __construct() {
        // WebSocket sunucusu başlat
        $this->startServer();
    }
    
    private function startServer() {
        // WebSocket protokolü kontrolü
        if (!isset($_SERVER['HTTP_UPGRADE']) || $_SERVER['HTTP_UPGRADE'] !== 'websocket') {
            $this->sendResponse(400, 'WebSocket upgrade required');
            return;
        }
        
        if (!isset($_SERVER['HTTP_CONNECTION']) || $_SERVER['HTTP_CONNECTION'] !== 'Upgrade') {
            $this->sendResponse(400, 'Connection upgrade required');
            return;
        }
        
        // WebSocket anahtarları
        $key = $this->generateWebSocketKey($_SERVER['HTTP_SEC_WEBSOCKET_KEY']);
        $acceptKey = base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
        
        // WebSocket handshake
        $this->sendResponse(101, 'Switching Protocols', [
            'Upgrade: websocket',
            'Connection: Upgrade',
            'Sec-WebSocket-Accept: ' . $acceptKey
        ]);
        
        // WebSocket mesaj döngüsü
        $this->handleWebSocketMessages();
    }
    
    private function generateWebSocketKey($key) {
        return base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
    }
    
    private function sendResponse($statusCode, $statusMessage = '', $headers = []) {
        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
        $statusText = $this->getHttpStatusText($statusCode);
        
        header($protocol . ' ' . $statusCode . ' ' . $statusText);
        
        foreach ($headers as $header) {
            header($header);
        }
        
        if ($statusCode >= 400) {
            echo json_encode(['error' => $statusMessage]);
        }
    }
    
    private function getHttpStatusText($code) {
        $status = [
            100 => 'Continue',
            101 => 'Switching Protocols',
            200 => 'OK',
            400 => 'Bad Request',
            401 => 'Unauthorized',
            404 => 'Not Found',
            500 => 'Internal Server Error'
        ];
        
        return isset($status[$code]) ? $status[$code] : 'Unknown';
    }
    
    private function handleWebSocketMessages() {
        // WebSocket mesajlarını dinle
        while (ob_get_level() == 0) {
            $data = $this->readWebSocketData();
            
            if ($data === false) {
                break;
            }
            
            $message = $this->parseWebSocketFrame($data);
            
            if ($message) {
                $this->processMessage($message);
            }
        }
    }
    
    private function readWebSocketData() {
        // WebSocket verisi oku (basit implementasyon)
        $data = '';
        $bytes = fread(STDIN, 8192);
        
        if ($bytes === false) {
            return false;
        }
        
        return $bytes;
    }
    
    private function parseWebSocketFrame($data) {
        // WebSocket frame parse (basit implementasyon)
        if (strlen($data) < 2) {
            return null;
        }
        
        $firstByte = ord($data[0]);
        $secondByte = ord($data[1]);
        
        $fin = ($firstByte & 0x80) === 0x80;
        $opcode = $firstByte & 0x0F;
        $masked = ($secondByte & 0x80) === 0x80;
        $payloadLength = $secondByte & 0x7F;
        
        if ($payloadLength === 126) {
            // Extended payload length (2 bytes)
            if (strlen($data) < 4) return null;
            $payloadLength = unpack('n', substr($data, 2, 2))[1];
            $maskKey = substr($data, 4, 4);
            $payloadData = substr($data, 8);
        } elseif ($payloadLength === 127) {
            // Extended payload length (8 bytes)
            if (strlen($data) < 10) return null;
            $payloadLength = unpack('J', substr($data, 2, 8))[1];
            $maskKey = substr($data, 10, 4);
            $payloadData = substr($data, 14);
        } else {
            // Short payload length
            $maskKey = substr($data, 2, 4);
            $payloadData = substr($data, 6);
        }
        
        // Maskeyi çöz
        if ($masked) {
            $unmasked = '';
            for ($i = 0; $i < strlen($payloadData); $i++) {
                $unmasked .= $payloadData[$i] ^ $maskKey[$i % 4];
            }
            $payloadData = $unmasked;
        }
        
        return [
            'fin' => $fin,
            'opcode' => $opcode,
            'masked' => $masked,
            'payload' => $payloadData,
            'length' => $payloadLength
        ];
    }
    
    private function processMessage($message) {
        if ($message['opcode'] !== 1) { // 1 = text frame
            return;
        }
        
        $data = json_decode($message['payload'], true);
        
        if (!$data) {
            $this->sendWebSocketMessage(['error' => 'Invalid JSON']);
            return;
        }
        
        switch ($data['type']) {
            case 'get_devices':
                $this->getDevices();
                break;
            case 'get_device_details':
                $this->getDeviceDetails($data['device_id']);
                break;
            case 'subscribe':
                $this->subscribeToDevice($data['device_id']);
                break;
            case 'unsubscribe':
                $this->unsubscribeFromDevice($data['device_id']);
                break;
            case 'ping':
                $this->sendWebSocketMessage(['type' => 'pong']);
                break;
        }
    }
    
    private function getDevices() {
        $stmt = $con->prepare("SELECT id, device_id, name, esp_model, status, current_mode FROM devices");
        $stmt->execute();
        $result = $stmt->get_result();
        
        $devices = [];
        while ($row = $result->fetch_assoc()) {
            $devices[] = [
                'id' => $row['id'],
                'device_id' => $row['device_id'],
                'name' => $row['name'],
                'esp_model' => $row['esp_model'],
                'status' => $row['status'],
                'current_mode' => $row['current_mode']
            ];
        }
        
        $this->sendWebSocketMessage([
            'type' => 'device_list',
            'devices' => $devices
        ]);
    }
    
    private function getDeviceDetails($deviceId) {
        $stmt = $con->prepare("
            SELECT d.*, 
                   (SELECT COUNT(*) FROM sensor_data sd WHERE sd.device_id = d.id) as sensor_count,
                   (SELECT JSON_ARRAYAGG(
                       JSON_OBJECT(
                           'sensor_code', sd.sensor_code,
                           'value', sd.value,
                           'unit', sd.unit,
                           'timestamp', sd.timestamp
                       )
                   ) FROM (
                       SELECT sensor_code, value, unit, timestamp
                       FROM sensor_data sd 
                       WHERE sd.device_id = d.id 
                       ORDER BY sd.timestamp DESC 
                       LIMIT 5
                   ) sd) as latest_sensors
            FROM devices d 
            WHERE d.id = ?
        ");
        $stmt->bind_param("i", $deviceId);
        $stmt->execute();
        $result = $stmt->get_result();
        
        if ($result->num_rows > 0) {
            $device = $result->fetch_assoc();
            
            // JSON alanlarını çöz
            $device['sensor_config'] = json_decode($device['sensor_config'], true);
            $device['motor_config'] = json_decode($device['motor_config'], true);
            $device['protection_config'] = json_decode($device['protection_config'], true);
            
            $this->sendWebSocketMessage([
                'type' => 'device_details',
                'device' => $device
            ]);
        }
    }
    
    private function subscribeToDevice($deviceId) {
        // İstemciyi cihaza abone et
        $this->clients[] = [
            'device_id' => $deviceId,
            'timestamp' => time()
        ];
        
        $this->sendWebSocketMessage([
            'type' => 'subscribed',
            'device_id' => $deviceId,
            'message' => 'Cihaza abone oldunuz'
        ]);
    }
    
    private function unsubscribeFromDevice($deviceId) {
        // İstemcinin aboneliğini kaldır
        $this->clients = array_filter($this->clients, function($client) use ($deviceId) {
            return $client['device_id'] !== $deviceId;
        });
        
        $this->sendWebSocketMessage([
            'type' => 'unsubscribed',
            'device_id' => $deviceId,
            'message' => 'Cihaz aboneliği kaldırıldı'
        ]);
    }
    
    private function sendWebSocketMessage($data) {
        // WebSocket mesajı gönder (basit implementasyon)
        $message = json_encode($data);
        $frame = $this->createWebSocketFrame($message);
        
        echo $frame;
        ob_flush();
        flush();
    }
    
    private function createWebSocketFrame($message) {
        $length = strlen($message);
        $frame = '';
        
        // Frame header
        $frame .= chr(0x81); // FIN + opcode (1 = text)
        
        // Payload length
        if ($length <= 125) {
            $frame .= chr($length);
        } elseif ($length <= 65535) {
            $frame .= chr(126) . pack('n', $length);
        } else {
            $frame .= chr(127) . pack('J', $length);
        }
        
        // Payload
        $frame .= $message;
        
        return $frame;
    }
    
    public function broadcastSensorData($deviceId, $sensorData) {
        // Tüm abone olmuş istemcilere sensör verisi gönder
        $subscribers = array_filter($this->clients, function($client) use ($deviceId) {
            return $client['device_id'] === $deviceId;
        });
        
        if (!empty($subscribers)) {
            $this->sendWebSocketMessage([
                'type' => 'sensor_data',
                'device_id' => $deviceId,
                'data' => $sensorData
            ]);
        }
    }
    
    public function broadcastDeviceStatus($deviceId, $status) {
        // Tüm abone olmuş istemcilere cihaz durumu gönder
        $subscribers = array_filter($this->clients, function($client) use ($deviceId) {
            return $client['device_id'] === $deviceId;
        });
        
        if (!empty($subscribers)) {
            $this->sendWebSocketMessage([
                'type' => 'device_status',
                'device_id' => $deviceId,
                'status' => $status
            ]);
        }
    }
    
    public function broadcastAlert($alert) {
        // Tüm istemcilere uyarı gönder
        $this->sendWebSocketMessage([
            'type' => 'alert',
            'alert' => $alert
        ]);
    }
}

// WebSocket sunucusunu başlat
$server = new WebSocketServer();
?>
