<?php

include 'fns/registry/load.php';
include 'include/config.php';

Registry::__init();
$config->ws_instance = true;

$ws_daemonize = true;

date_default_timezone_set('Asia/Kolkata');

include 'fns/global/load.php';

$sys_settings = extract_json(['file' => 'assets/cache/settings.cache']);

$url_info = $sys_settings->site_address;

$config = (object) array_merge((array) $config, (array)$url_info);

Registry::add('config', $config);

include_once 'fns/sql/load.php';
include_once 'fns/SleekDB/Store.php';

if ($config->developer_mode) {
    $ws_daemonize = false;
}

$ws_host = $sys_settings->websocket_host;
$ws_port = $sys_settings->websocket_port;

$ws_protocol = $sys_settings->websocket_protocol;

$ws_ssl_certificate = $sys_settings->websocket_ssl_certificate;
$ws_private_key = $sys_settings->websocket_private_key;

if (!empty($ws_port)) {
    $ws_instance = new Swoole\Websocket\Server($ws_host, $ws_port);
} else {
    $ws_instance = new Swoole\Websocket\Server($ws_host);
}

if ($ws_protocol === 'ssl') {
    $ws_instance->set([
        'ssl_cert_file' => $ws_ssl_certificate,
        'ssl_key_file' => $ws_private_key,
    ]);
}

if ($ws_daemonize) {
    $ws_instance->set([
        'daemonize' => true,
    ]);
}

$ws_clients = $ws_users = $monitoring_private_chat = [];

$total_users_online = 0;

DB::connect()->update('site_users', ['online_status' => 0]);

$ws_instance->on("open", function ($ws_instance, $request) use (&$ws_clients, &$total_users_online, &$ws_users) {

    $total_users_online = (int)$total_users_online+1;

    $login_session_id = $request->get['login_session_id'] ?? null;
    $access_code = $request->get['access_code'] ?? null;
    $session_time_stamp = $request->get['session_time_stamp'] ?? null;

    include 'fns/variables/load.php';

    $ws_clients[$request->fd] = [
        'fd' => $request->fd,
        'logged_in' => Registry::load('current_user')->logged_in,
        'user_id' => Registry::load('current_user')->id,
        'info' => Registry::load('current_user'),
        'permissions' => Registry::load('permissions'),
        'strings' => Registry::load('strings'),
    ];

    if (Registry::load('current_user')->logged_in && !empty(Registry::load('current_user')->username)) {

        $user_id = Registry::load('current_user')->id;

        $ws_users[$user_id] = $request->fd;

        echo "@".Registry::load('current_user')->username." is currently online".PHP_EOL;


        $update_status = [
            'online_status' => 1,
            "last_seen_on" => Registry::load('current_user')->time_stamp,
            "updated_on" => Registry::load('current_user')->time_stamp,
        ];
        DB::connect()->update('site_users', $update_status, ['user_id' => $user_id]);

        $ws_data = ['update' => 'online_users'];
        include 'fns/realtime/ws_process_data.php';
    } else {
        echo "A non-logged-in user is currently online".PHP_EOL;
    }

    echo "Total Online Users: ".$total_users_online.PHP_EOL;

});

$ws_instance->on("request", function ($request, $response) use (&$ws_instance, &$ws_clients, &$ws_users, &$monitoring_private_chat) {
    try {
        $ws_data = json_decode($request->rawContent(), true);

        if (isset($ws_data['ws_transmit_code']) && !empty($ws_data['ws_transmit_code'])) {
            $ws_transmit_code_file = 'assets/cache/ws_transmit_code.cache';

            if (file_exists($ws_transmit_code_file)) {
                $ws_transmit_code = trim(file_get_contents($ws_transmit_code_file));

                if (!empty($ws_transmit_code) && $ws_data['ws_transmit_code'] === $ws_transmit_code) {
                    if (isset($ws_data['update'])) {
                        include 'fns/realtime/ws_process_data.php';
                    }
                } else {
                    echo 'Unauthorized: Invalid secure code';
                }
            }
        }
    } catch (Exception $e) {
        $web_socket_error = "WebSocket Message Error: " . $e->getMessage() . PHP_EOL;
    }
});


$ws_instance->on("message", function ($ws_instance, $frame) use (&$ws_clients, &$ws_users, &$monitoring_private_chat) {
    try {
        $ws_data = json_decode($frame->data, true);
        $fd = $frame->fd;


        if (isset($ws_data['type']) && $ws_data['type'] === "chat_context" && isset($ws_data['payload'])) {

            $payload = $ws_data['payload'];
            $process_ws_data = false;

            if (isset($ws_clients[$fd]['chat_context'])) {

                if (isset($payload["userFpToken"]) && !isset($ws_clients[$fd]['userFpToken'])) {
                    $ws_data = ['update' => 'user_fp_token'];
                    $process_ws_data = true;
                }

                $prev_chat_context = $ws_clients[$fd]['chat_context'];

                if (!isset($prev_chat_context['user_id'])) {
                    $prev_chat_context['user_id'] = null;
                }

                if (!isset($prev_chat_context['group_id'])) {
                    $prev_chat_context['group_id'] = null;
                }

                if (isset($payload['user_id']) && $payload['user_id'] === 'all') {
                    $monitoring_private_chat[$fd] = $ws_clients[$fd]['user_id'];
                } else {
                    if (isset($monitoring_private_chat[$fd])) {
                        unset($monitoring_private_chat[$fd]);
                    }
                }

                if (isset($payload['user_id']) && isset($prev_chat_context['user_id'])) {
                    if ((int)$payload['user_id'] !== (int)$prev_chat_context['user_id']) {
                        $ws_data = ['update' => 'last_seen_by_recipient', 'receiver_id' => $payload['user_id'], 'sender_id' => $ws_clients[$fd]['user_id']];
                        $process_ws_data = true;
                    }
                } else if (isset($payload['group_id']) && isset($prev_chat_context['group_id'])) {
                    if ((int)$payload['group_id'] !== (int)$prev_chat_context['group_id']) {
                        $ws_data = ['update' => 'new_group_video_call'];
                        $process_ws_data = true;
                    }
                }
            }


            if ($process_ws_data) {
                include 'fns/realtime/ws_process_data.php';
            }

            $ws_clients[$fd]['chat_context'] = $payload;
        }
    } catch (Exception $e) {
        $web_socket_error = "WebSocket Message Error: " . $e->getMessage() . PHP_EOL;
    }

});

$ws_instance->on("close", function ($ws_instance, $fd) use (&$ws_clients, &$total_users_online, &$ws_users, &$monitoring_private_chat) {
    if (!isset($ws_clients[$fd])) {
        return;
    }

    $user_id = $ws_clients[$fd]['user_id'];

    $other_fd_exists = false;
    foreach ($ws_clients as $client_fd => $client) {
        if ($client['user_id'] === $user_id && $client_fd !== $fd) {
            $other_fd_exists = true;
            break;
        }
    }

    if (isset($monitoring_private_chat[$fd])) {
        unset($monitoring_private_chat[$fd]);
    }

    if (isset($ws_users[$user_id])) {
        unset($ws_users[$user_id]);
    }

    echo "User {$user_id} (FD {$fd}) has disconnected." . PHP_EOL;

    unset($ws_clients[$fd]);
    $total_users_online--;

    echo "Total Online Users: {$total_users_online}" . PHP_EOL;

    $update_status = [
        'online_status' => 0,
        "last_seen_on" => Registry::load('current_user')->time_stamp,
        "updated_on" => Registry::load('current_user')->time_stamp,
    ];
    DB::connect()->update('site_users', $update_status, ['user_id' => $user_id]);

    $ws_data = ['update' => 'online_users'];
    include 'fns/realtime/ws_process_data.php';


});

if (isset(Registry::load('config')->pro_version) && !empty(Registry::load('config')->pro_version)) {
    Swoole\Timer::tick(900000, function() {
        include('fns/realtime/sys_validate_memberships.php');
    });

}


$ws_instance->start();
?>