package CF2022::Helpers::Auth;

use base 'Mojolicious::Plugin';
use Mojo::UserAgent;
use Mojo::JWT;

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

use constant KEY_FORMAT => "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----";
use constant REGIONS    => qr{^(jhc|jhm|kvk|lbk|msk|olk|pak|pha|plk|stc|ulk|vys|zlk|khk):(f|regp)$};

sub register ( $class, $self, $conf) {

    my $ua  = Mojo::UserAgent->new();
    my ( $jwt, $groups);

    $self->helper( jwt => sub {
        if ( ! $jwt ) {

            if ( $self->cfg->{test} && $self->cfg->{test_auth_jwt_secret}) {
                $jwt = Mojo::JWT->new(
                    secret => $self->cfg->{test_auth_jwt_secret}
                );
                return $jwt;
            }

            my $res;
            eval { $res = $ua->get( $self->cfg->{oauth_url} )->result; };

            if (! $@ && $res->is_success) {
                $jwt = Mojo::JWT->new(
                    public => sprintf( KEY_FORMAT,  $res->json->{public_key} )
                );
            }
        }
        return $jwt;
    });

    $self->helper( oauth_groups => sub ( $c ) {
        if ( ! $groups ) {
            my $res;

            eval { $res = $ua->get( $self->cfg->{groups_url} )->result; };

            if (! $@ && $res->is_success) {
                my $json = $res->json;
                $groups = { map { $_->{code} => $_->{name} } @{ $json } };
            }
        }
        return $groups;
    });

    $self->helper( oauth_token => sub ( $c, $token='' ) {
        $c->stash->{token} //= $token;
        return $c->stash->{token};
    });

    $self->helper( oauth_claims => sub ( $c ) {
        if ( ! $c->stash->{claims}) {

            return undef if ! ($c->jwt && $c->oauth_token);

            my $claims;
            eval { $claims = $c->jwt->decode( $c->oauth_token );  };

            if ( $@ ) {
                $c->app->log->warn("Invalid token ($@)");
            }

            $c->stash->{claims} = $claims;
        }

        return $c->stash->{claims};
    });

    $self->helper( oauth_main_group => sub ( $c ) {
        my $claims = $c->oauth_claims // return;

        GROUP:
        foreach my $group ( sort @{ $claims->{groups} } ) {
            if ( $group =~ REGIONS ) {
                my $role = ( $2 eq 'f') ? 'member':'regp';

                my $region = $c->oauth_groups->{ $group };
                $region =~ s/^K[SF]\s+//i;

                return {
                    region => $region,
                    role   => $role,
                };
            }
            elsif ( $group =~ /cen:regp/ ) {
                return {
                    region => 'Celostátní fórum',
                    role   => 'regp',
                };
            }
        }
    });

    $self->helper( user => sub ( $c ) {
        my $claims = $c->oauth_claims // return undef;

        if ( ! $c->stash->{user} ) {
            $c->stash->{user} = {
                uuid     => $claims->{sub},
                username => $claims->{preferred_username},
                name     => $claims->{name},
#               groups   => $claims->{groups},
                main_group_name => $c->oauth_main_group_name(),
            };
        }
        return $c->stash->{user};
    });


}

1;

__END__