package CF::Controller::Websockets;

use Mojo::Base 'Mojolicious::Controller';
use Mojo::Pg::PubSub;
use Digest::SHA qw(hmac_sha1_hex);
use Encode qw(encode decode);

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

use constant SOCKET_INACTIVITY_TIMEOUT => 180;
use constant ALIVE_TIME                => 60;

sub main {
    my $c  = shift;
    $c->inactivity_timeout(SOCKET_INACTIVITY_TIMEOUT);
    $c->tx->with_compression;

    my $key    = $c->req->headers->header('Sec-WebSocket-Key');
    my $pubsub = $c->redis->pubsub;
    my $user;
    my $event_id = 0; #TODO - parametr!

    my $listener = $pubsub->listen(
        "notify:$event_id" => sub($pubsub, $payload, $channel) {
            $c->send(decode("UTF-8", $payload));
        }
    );

    my $listener_online = $pubsub->listen(
        "online:$event_id" => sub($pubsub, $payload, $channel) {
            my @counts = split ' ', $payload;
            $c->send({json => {
                event   => 'online_users_updated',
                payload => {
                    all             => $counts[0]+0,
                    members         => $counts[1]+0,
                    group_size_full => $counts[2]+0,
                    group_size_half => $counts[3]+0,
                }
            }});
        }
    );

    $c->on(json => sub( $c, $message ) {
        if ( $message->{event} eq 'KEEPALIVE' ) {

            my $is_member = 0;

            if ($message->{payload} =~ /^\d+$/) {
                $user ||= $c->schema->resultset('User')->find({
                    id => $message->{payload},
                });
            }

            if ( $user ) {
                my $sig = hmac_sha1_hex($message->{payload}, $user->secret );
                if ( $sig ne $message->{sig} ) {
                    $c->app->log->warn(
                        "Invalid signature for " . $user->username
                    );
                }
                else {
                    $user->add_to_alive({ event_id => $event_id });
                    $is_member = 1 if $user && $user->roles =~ /member/;

                    my $jitsi = $user->jitsi_allowed || $user->roles =~ /chairman|jitsi/;

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

            $c->redis->db->set(
                join (':', ('live', $event_id, $is_member, $is_member ? $user->id : $key)),
                'live', 'EX', ALIVE_TIME
            );

        }
    });

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

1;