package SeMeet::Controller::Meets;
use Mojo::Base 'Mojolicious::Controller', -signatures;

use UUID::URandom qw(create_uuid_string);
use Mojo::JWT;

use constant AVATAR_SIZE          => 320;
use constant JITSI_TOKEN_LIFETIME => 3600 * 24;

sub create($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    return $c->error(403, 'Access denied') if ! $c->stash->{permissions}{create};

    my $exists = $c->schema->resultset('Meet')->count({
        deleted => undef,
        name    => $args->{name},
    });

    return $c->error(400, 'DUPLICTE_NAME') if $exists;

    my $guard  = $c->schema->txn_scope_guard;

        my $meet = $c->schema->resultset('Meet')->create({
            uuid     => create_uuid_string(),
            owner_id => $c->stash->{user}->id,
            name     => $args->{name},
        });

    $guard->commit;

    $c->trace(\'User %s create meet "%s" with id %d',
        $c->stash->{user}->username,
        $meet->name,
        $meet->id,
    );

    $c->render(
        status  => 201,
        openapi => { id => $meet->id },
    );
}

sub get($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    my $meet = $c->_get($c->stash->{id}, 0) // return;

    my $users   = { 0 => [], 1 => [] };
    my @invites = ();

    USER:
    foreach my $user ( $meet->users ) {
        push @{ $users->{ $user->is_moderator} }, {
             id   => $user->id,
             name => $user->user_name,
        }
    }

    INVITE:
    foreach my $invite ( $meet->invites ) {
        push @invites, {
             id          => $invite->id,
             token       => $invite->token,
             displayname => $invite->displayname,
        }
    }

    $c->render(openapi => $c->spec_filter({
        $meet->get_columns,
        groups       => $meet->cached_groups, #TODO: direct
        moderators   => $users->{1},
        participants => $users->{0},
        invites      => \@invites,
    }, 'Meet'));
}

sub list($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    my $meets = $c->schema->resultset('Meet')->search({
        deleted  => undef,
        -or => [
            owner_id => $c->stash->{user}->id,
            "meet_groups.group_id" => { '-in' => $c->stash->{groups} },
            "meet_users.user_id" => $c->stash->{user}->id,
        ]
    },
    {
        order_by => 'name',
        join     => ['meet_groups', 'meet_users'],
        distinct => 1,
    }
    );

    my @meets = ();

    MEET:
    while ( my $meet = $meets->next()) {
        push @meets, $c->spec_filter({
            $meet->get_columns,
            groups       => $meet->cached_groups,
            moderators   => $meet->cached_moderators,
            participants => [],
            invites      => [],
        }, 'Meet')
    }

    $c->render(
        openapi => {
            count   => scalar( @meets ),
            records => \@meets,
        },
    );
}

sub add_groups($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    my $meet = $c->_get($c->stash->{id}, 1) // return;

    IDS:
    foreach my $id ( @{ $args->{groups} } ) {
        $meet->find_or_create_related('meet_groups',
            { group_id => $id }
        );
    }
    $meet->update_groups_cache();

    $c->render( status  => 204, text => '' );
}

sub delete_group($c) {
    $c->openapi->valid_input or return;

    my $meet = $c->_get($c->stash->{id}, 1) // return;

    $meet->delete_related('meet_groups',
        { group_id => $c->stash->{group_id} }
    );
    $meet->update_groups_cache();

    $c->render( status  => 204, text => '' );
}

sub add_users($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    my $meet = $c->_get($c->stash->{id}, 2) // return;
    my $is_moderator = $args->{kind} eq 'moderator' ? 't':'f';

    UUID:
    foreach my $uuid ( @{ $args->{users} } ) {
        my $user = $c->user_by_uuid($uuid) // next UUID;
        $meet->find_or_create_related('meet_users',
            {
                user_id       => $user->id,
                is_moderator  => $is_moderator,
            }
        );
    }
    $meet->update_moderators_cache() if $is_moderator;

    $c->render( status  => 204, text => '' );
}

sub delete_user($c) {
    $c->openapi->valid_input or return;

    my $meet = $c->_get($c->stash->{id}, 2) // return;

    $meet->delete_related('meet_users',
        { id => $c->stash->{relation_id} }
    );

    $meet->update_moderators_cache();

    $c->render( status  => 204, text => '' );
}

sub delete_invite($c) {
    $c->openapi->valid_input or return;

    my $meet = $c->_get($c->stash->{id}, 2) // return;

    $meet->delete_related('invites',
        { id => $c->stash->{invite_id} }
    );

    $c->render( status  => 204, text => '' );
}

sub delete($c) {
    $c->openapi->valid_input or return;

    my $meet = $c->_get($c->stash->{id}, 2) // return;

    $meet->update({ deleted => \'now()'});

    $c->render( status  => 204, text => '' );
}

sub update($c) {
    $c->openapi->valid_input or return;
    my $args = $c->req->json;

    my $meet = $c->_get($c->stash->{id}, 2) // return;

    my $exists = $c->schema->resultset('Meet')->count({
        id      => { '!=' => $meet->id },
        deleted => undef,
        name    => $args->{name},
    });

    return $c->error(400, 'DUPLICTE_NAME') if $exists;

    $meet->update({
        name        => $args->{name},
        description => $args->{description},
    });

    $c->render( status  => 204, text => '' );
}

sub meet($c) { #NENI API!

    my $meet = $c->schema->resultset('Meet')->find({
        id => $c->stash->{id}
    });

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

    if (! $meet) {
        $c->render('unauthorized');
        return;
    }
#    return $c->error(404, 'NOT_FOUND') if ! $meet;

    my $roles = $meet->user_roles($user, $c->current_user->{groups});
    $c->trace($roles);

#    return $c->error(404, 'NOT_FOUND') if ! $roles->{any};
    if (! $roles->{any}) {
        $c->render('unauthorized');
        return;
    }

    $c->stash->{meet}  = $meet;
    $c->stash->{roles} = $roles;
    $c->stash->{token} = $user->meet_token($meet, $c->config);

    $c->render('meet');
}

sub _get($c, $id, $access) {

    my $meet = $c->schema->resultset('Meet')->find({ id => $id });
    return $c->error(404, 'NOT_FOUND') if ! $meet;

    my $roles = $meet->user_roles($c->stash->{user}, $c->stash->{groups});
    return $c->error(403, 'ACCESS_DENIED') if ! $roles->{any};

    if ( $access == 1 && ! ($roles->{moderator} || $roles->{owner}) ) {
        return $c->error(403, 'ACCESS_DENIED');
    }

    if ( $access == 2 && ! $roles->{owner} ) {
        return $c->error(403, 'ACCESS_DENIED');
    }

    return $meet;
}

1;