package CF::Controller::Websockets;

use Mojo::Base 'Mojolicious::Controller';
use Mojo::Pg::PubSub;
use Digest::SHA qw(hmac_sha1_hex);
use POSIX qw(ceil);

use feature 'signatures';
no warnings qw{ experimental::signatures };

use constant SOCKET_INACTIVITY_TIMEOUT => 300;

sub main {
    my $c  = shift;
    my $ip = $c->tx->remote_address;

    $c->inactivity_timeout(SOCKET_INACTIVITY_TIMEOUT);

    my $pubsub = Mojo::Pg::PubSub->new(pg => $c->pg);

    $pubsub->listen(notify => sub($pubsub, $payload) {
        $c->send($payload);
    });

    $c->on(json => sub( $c, $message ) {

        if ( $message->{event} eq 'KEEPALIVE' ) {
            my $user;

            if ($message->{payload} =~ /^(\d+)$/) {
                # TODO: check signtaure

                $user = $c->schema->resultset('User')->find(
                    { id => $1 }
                );
            }

            $c->schema->resultset('Socket')->update_or_create({
                id        => $c->req->headers->header('Sec-WebSocket-Key'),
                ip        => $ip,
                keepalive => \'now()',
                user_id   => $user ? $user->id : undef,
            }, { key => $user ? 'user':'primary'} );

            my $all = $c->schema->resultset('Socket_view')->count(
                { is_alive => 't', }
            );

            my $members = $c->schema->resultset('Socket_view')->count(
                { is_alive => 't', is_member => 't' }
            );

            my $group_size = $c->_member_group_size($members);

            $c->send({json => { event => 'online_users_updated', payload => {
                all             => $all,
                members         => $members,
                group_size_full => $group_size->{full},
                group_size_half => $group_size->{half},
            }}});

            if ( $user ) {
                my $jitsi = $user->jitsi_allowed || $user->roles =~ /chairman/;

                $c->send({json => { event => 'user_status', payload => {
                    jitsi_allowed => $jitsi ? \1:\0,
#                   is_banned     => $user->banned_until ? 1:0,
                }}});
            }
        }

    });

    $c->on(finish => sub ($c, $code, $reason = undef) {
        $pubsub->unlisten('notify');
        $c->app->log->debug("WebSocket closed with status $code");
    });
}

sub _member_group_size  ($c, $total = 0){
    my $group = 2 * sqrt($total);
    my $min   = $total / 100;
    my $max   = $total / 5;

    $group = $min if $group < $min;
    $group = $max if $group > $max;

    return {
        full => ceil( $group ),
        half => ceil( $group/2 ),
    };
}

1;