package SeMeet;

use Mojo::Base 'Mojolicious', -signatures;
use Mojo::Pg;
use Mojo::Redis;
use Mojolicious::Plugin::Authentication;
use Mojolicious::Plugin::I18N;
use Net::OAuth2::Profile::WebServer;
use File::Find;
use Path::Tiny qw( path );
use SeMeet::Schema;
use SeMeet::Model::IAPI;

use constant SECRETS => '/run/secrets';

sub startup( $self ) {

    # Nacteni konfigurace
    my $cfg = $self->plugin('Config' => { file => 'semeet.conf'} );

    # env z docker secrets
    find(sub { $ENV{$_} = path(SECRETS . "/$_")->slurp_utf8 }, SECRETS);

    # Konfigurace z ENV ma prednost
    KEY:
    foreach my $key ( keys %ENV ) {
        if ( $key =~ /^CFG_(.+)/i ) {
            $cfg->{lc($1)} = $ENV{$key};
        }
    }
    $self->helper( cfg => sub { return $cfg; } );

    # Podpis pro cookies
    $self->secrets([$cfg->{session_secret}]);

    # Delka session
    $self->sessions->default_expiration($cfg->{session_lifetime} // 24 * 3600);

    $self->plugin('SeMeet::Helpers::Core');
    $self->plugin('SeMeet::Helpers::OIDC');

    # migrace schematu
    my $pg = Mojo::Pg->new
        ->dsn($cfg->{database}{dsn})
        ->username($cfg->{database}{user})
        ->password($cfg->{database}{password})
    ;
    $pg->migrations->from_file($self->home . '/sql/migrations.sql');
    $pg->migrations->migrate();
    $self->helper( pg => sub { return $pg; } );

    # Spojeni s databazi
    my $schema = SeMeet::Schema->connect($cfg->{database});
    $self->helper( schema => sub { return $schema; } );

    # Redis
    my $iapi = SeMeet::Model::IAPI->new( $cfg->{iapi} );
    $self->helper( iapi => sub { return $iapi; } );

    # Redis
    my $redis = Mojo::Redis->new( $cfg->{redis} );
    $self->helper( redis => sub { return $redis; } );

    # i18n
    $self->plugin( I18N => {
        namespace => 'SeMeet::I18N',
        default   => 'cs',
    });

    $self->plugin('authentication', {
        autoload_user => 1,
        load_user => sub($c, $uid) {
            return  $c->session->{user};
        },
        validate_user => sub($c, $user, $pass, $extradata) {
            return  $c->session->{user} ? 1 : undef;
        },
    });

    $self->plugin("OpenAPI" => {
        url      => $self->home->rel_file("openapi.yaml"),
        schema => 'v3',
        plugins                        => [qw(+Cors +Security)],
        render_specification           => 0,
        render_specification_for_paths => 0,
        default_response_codes         => [400, 401, 403, 404, 500, 501],

        security => {
            Bearer => sub ($c, $definition, $scopes, $cb ){
#                my ($c, $definition, $scopes, $cb ) = @_;

                my $token = $c->req->headers->authorization || $c->req->param('auth_token');

                return $c->$cb('Authorization header not present') if ! $token;
                return $c->$cb('Unsupported authorization type') if $token !~ s/Bearer\s+//i;

                my $jwt = $c->jwt_token( $token );
                return $c->$cb($jwt) if ! ref $jwt;

                my $user = $schema->resultset('User')->find({ id => $jwt->{id} } );
                return $c->$cb('Invalid user') if ! $user;

                $c->stash->{user}        = $user;
                $c->stash->{groups}      = $jwt->{groups};
                $c->stash->{permissions} = $jwt->{permissions};

                return $c->$cb();
            }
        }
    });

    # defautni globalni promenne ve stash
    $self->defaults(
        openapi_cors_allowed_origins => ['*'],
    );

    $self->hook( before_render => sub($c, $args) {
        if ( $c->req->method eq 'OPTIONS' && exists $args->{json} ) {
            delete $args->{json};
            $args->{status} = 204;
            $args->{text} = '';
        }
    });
    # vypnuti cache templatu pri vyvoji
    $self->renderer->cache->max_keys(0) if $cfg->{dev_mode};

    # router
    my $r = $self->routes;

    $r->get('/login')->to('Auth#callback');
    $r->get('/logout')->to('Auth#do_logout');

    $r->get('/')->requires(authenticated => 1)->to(cb => sub { shift->render('meets'); });
    $r->get('/')->to(cb => sub { shift->render('index'); });

    $r->get('/meets/:id')->requires(authenticated => 1)->to('Meets#meet');
    $r->get('/meets/:id')->to(cb => sub {
        my $c = shift;
        $c->session->{id} = $c->stash->{id};
        $c->render('index');
    });
    $r->get('/guest/:token')->to('Invites#meet');

    $r->websocket('/ws')->to('Websockets#main');
}

1;