<?php
/**
 * ============================================================================
 * websocket-server.php - WebSocket Server for Real-time Chat
 * ============================================================================
 * Run this file from command line: php websocket-server.php
 */

require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/config/config.php';

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class ChatServer implements MessageComponentInterface {
    protected $clients;
    protected $users;
    protected $db;
    
    public function __construct() {
        $this->clients = new \SplObjectStorage;
        $this->users = [];
        
        // Database connection
        $database = new \App\Database();
        $this->db = $database->getConnection();
        
        echo "WebSocket server started on port 8080\n";
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        try {
            $data = json_decode($msg, true);
            
            if (!$data || !isset($data['type'])) {
                return;
            }
            
            switch ($data['type']) {
                case 'auth':
                    $this->handleAuth($from, $data);
                    break;
                    
                case 'message':
                    $this->handleMessage($from, $data);
                    break;
                    
                case 'typing':
                    $this->handleTyping($from, $data);
                    break;
                    
                case 'read':
                    $this->handleRead($from, $data);
                    break;
                    
                case 'online':
                    $this->handleOnlineStatus($from, $data);
                    break;
                    
                default:
                    echo "Unknown message type: {$data['type']}\n";
            }
            
        } catch (\Exception $e) {
            echo "Error handling message: " . $e->getMessage() . "\n";
        }
    }

    public function onClose(ConnectionInterface $conn) {
        // Remove user from online list
        $userId = $this->getUserIdByConnection($conn);
        if ($userId) {
            unset($this->users[$userId]);
            $this->broadcastOnlineStatus($userId, false);
        }
        
        $this->clients->detach($conn);
        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";
        $conn->close();
    }
    
    /**
     * Handle user authentication
     */
    private function handleAuth($conn, $data) {
        if (!isset($data['user_id']) || !isset($data['token'])) {
            return;
        }
        
        // Verify token (you should implement proper JWT or session verification)
        $userId = (int)$data['user_id'];
        
        // Store user connection
        $this->users[$userId] = $conn;
        
        // Update user's last activity in database
        $stmt = $this->db->prepare("UPDATE users SET last_activity = NOW() WHERE id = ?");
        $stmt->execute([$userId]);
        
        // Send confirmation
        $conn->send(json_encode([
            'type' => 'auth_success',
            'user_id' => $userId
        ]));
        
        // Broadcast online status
        $this->broadcastOnlineStatus($userId, true);
        
        echo "User {$userId} authenticated\n";
    }
    
    /**
     * Handle new message
     */
    private function handleMessage($from, $data) {
        if (!isset($data['chat_id']) || !isset($data['recipient_id']) || !isset($data['message_id'])) {
            return;
        }
        
        $senderId = $this->getUserIdByConnection($from);
        if (!$senderId) {
            return;
        }
        
        $recipientId = (int)$data['recipient_id'];
        $chatId = (int)$data['chat_id'];
        $messageId = (int)$data['message_id'];
        
        // Get full message details from database
        $stmt = $this->db->prepare("
            SELECT m.*, u.full_name as sender_name, u.profile_picture as sender_avatar
            FROM messages m
            JOIN users u ON m.sender_id = u.id
            WHERE m.id = ?
        ");
        $stmt->execute([$messageId]);
        $message = $stmt->fetch(\PDO::FETCH_ASSOC);
        
        if (!$message) {
            return;
        }
        
        // Send to recipient if online
        if (isset($this->users[$recipientId])) {
            $this->users[$recipientId]->send(json_encode([
                'type' => 'new_message',
                'chat_id' => $chatId,
                'message' => $message
            ]));
            
            echo "Message sent from {$senderId} to {$recipientId}\n";
        } else {
            echo "Recipient {$recipientId} is offline\n";
        }
    }
    
    /**
     * Handle typing indicator
     */
    private function handleTyping($from, $data) {
        if (!isset($data['chat_id']) || !isset($data['recipient_id']) || !isset($data['typing'])) {
            return;
        }
        
        $senderId = $this->getUserIdByConnection($from);
        if (!$senderId) {
            return;
        }
        
        $recipientId = (int)$data['recipient_id'];
        $chatId = (int)$data['chat_id'];
        $isTyping = (bool)$data['typing'];
        
        // Send typing status to recipient if online
        if (isset($this->users[$recipientId])) {
            $this->users[$recipientId]->send(json_encode([
                'type' => 'typing',
                'chat_id' => $chatId,
                'user_id' => $senderId,
                'typing' => $isTyping
            ]));
        }
    }
    
    /**
     * Handle read receipt
     */
    private function handleRead($from, $data) {
        if (!isset($data['chat_id']) || !isset($data['recipient_id'])) {
            return;
        }
        
        $userId = $this->getUserIdByConnection($from);
        if (!$userId) {
            return;
        }
        
        $recipientId = (int)$data['recipient_id'];
        $chatId = (int)$data['chat_id'];
        
        // Update last read in database
        $stmt = $this->db->prepare("
            UPDATE chat_members 
            SET last_read_at = NOW() 
            WHERE chat_id = ? AND user_id = ?
        ");
        $stmt->execute([$chatId, $userId]);
        
        // Send read receipt to sender if online
        if (isset($this->users[$recipientId])) {
            $this->users[$recipientId]->send(json_encode([
                'type' => 'read',
                'chat_id' => $chatId,
                'user_id' => $userId
            ]));
        }
    }
    
    /**
     * Handle online status update
     */
    private function handleOnlineStatus($from, $data) {
        $userId = $this->getUserIdByConnection($from);
        if (!$userId) {
            return;
        }
        
        // Update last activity
        $stmt = $this->db->prepare("UPDATE users SET last_activity = NOW() WHERE id = ?");
        $stmt->execute([$userId]);
    }
    
    /**
     * Broadcast user's online status to their contacts
     */
    private function broadcastOnlineStatus($userId, $isOnline) {
        // Get user's chat partners
        $stmt = $this->db->prepare("
            SELECT DISTINCT cm2.user_id
            FROM chats c
            JOIN chat_members cm1 ON c.id = cm1.chat_id
            JOIN chat_members cm2 ON c.id = cm2.chat_id
            WHERE c.chat_type = 'one_to_one'
            AND cm1.user_id = ?
            AND cm2.user_id != ?
        ");
        $stmt->execute([$userId, $userId]);
        $contacts = $stmt->fetchAll(\PDO::FETCH_COLUMN);
        
        // Send status to online contacts
        foreach ($contacts as $contactId) {
            if (isset($this->users[$contactId])) {
                $this->users[$contactId]->send(json_encode([
                    'type' => 'user_status',
                    'user_id' => $userId,
                    'online' => $isOnline
                ]));
            }
        }
    }
    
    /**
     * Get user ID by connection
     */
    private function getUserIdByConnection($conn) {
        foreach ($this->users as $userId => $userConn) {
            if ($userConn === $conn) {
                return $userId;
            }
        }
        return null;
    }
}

// Start the WebSocket server
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new ChatServer()
        )
    ),
    8080
);

echo "Starting WebSocket server...\n";
$server->run();