<?php

declare(strict_types=1);

namespace App\Application\Http\Controllers;

use App\Framework\Attributes\Route;
use App\Framework\Auth\Auth;
use App\Framework\Http\Method;
use App\Framework\Http\WebSocketConnection;
use App\Framework\Router\Result\WebSocketResult;

final class ChatController
{
    /** @var array<string, WebSocketConnection> */
    private array $connections = [];

    #[Auth]
    #[Route(path: '/chat/websocket', method: Method::GET)]
    public function chatWebSocket(): WebSocketResult
    {
        return new WebSocketResult()
            ->onConnect(function (WebSocketConnection $connection) {
                $this->connections[$connection->getId()] = $connection;

                // Willkommensnachricht senden
                $connection->sendJson([
                    'type' => 'system',
                    'message' => 'Willkommen im Chat!',
                    'timestamp' => time(),
                ]);

                // Andere Benutzer benachrichtigen
                $this->broadcast([
                    'type' => 'user_joined',
                    'message' => 'Ein neuer Benutzer ist dem Chat beigetreten',
                    'timestamp' => time(),
                ], $connection->getId());
            })
            ->onMessage(function (WebSocketConnection $connection, string $message) {
                $data = json_decode($message, true);

                if (! $data || ! isset($data['type'])) {
                    $connection->sendJson(['error' => 'Invalid message format']);

                    return;
                }

                switch ($data['type']) {
                    case 'chat_message':
                        $this->handleChatMessage($connection, $data);

                        break;
                    case 'ping':
                        $connection->sendJson(['type' => 'pong']);

                        break;
                    default:
                        $connection->sendJson(['error' => 'Unknown message type']);
                }
            })
            ->onClose(function (WebSocketConnection $connection, int $code, string $reason) {
                unset($this->connections[$connection->getId()]);

                // Andere Benutzer benachrichtigen
                $this->broadcast([
                    'type' => 'user_left',
                    'message' => 'Ein Benutzer hat den Chat verlassen',
                    'timestamp' => time(),
                ]);
            })
            ->onError(function (WebSocketConnection $connection, \Throwable $error) {
                error_log("WebSocket error: " . $error->getMessage());
                $connection->close(1011, 'Internal server error');
            })
            ->withSubprotocols(['chat'])
            ->withMaxMessageSize(10240) // 10KB
            ->withPingInterval(30); // 30 Sekunden
    }

    private function handleChatMessage(WebSocketConnection $sender, array $data): void
    {
        if (! isset($data['message'])) {
            $sender->sendJson(['error' => 'Message content required']);

            return;
        }

        $message = [
            'type' => 'chat_message',
            'user_id' => $sender->getId(),
            'message' => $data['message'],
            'timestamp' => time(),
        ];

        // Nachricht an alle Verbindungen senden
        $this->broadcast($message);
    }

    private function broadcast(array $message, ?string $excludeId = null): void
    {
        foreach ($this->connections as $id => $connection) {
            if ($excludeId && $id === $excludeId) {
                continue;
            }

            if ($connection->isConnected()) {
                $connection->sendJson($message);
            } else {
                unset($this->connections[$id]);
            }
        }
    }
}
