package CF;
use Mojo::Base 'Mojolicious';
use Mojo::Pg;
use Mojo::JWT;
use Mojo::Redis;
use CF::Schema;

# This method will run once at server start
sub startup {
    my $self = shift;

    my $cfg = $self->plugin('Config' => { file => 'cf.conf'} );
    $self->helper( cfg => sub { return $cfg; } );

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

    # migrace schematu
    my $pg = Mojo::Pg->new
        ->dsn($cfg->{db_dsn})
        ->username($cfg->{db_username})
        ->password($cfg->{db_password})
    ;
    if ($cfg->{test}) {
        $pg->search_path(['test']);
        $pg->db->query('drop schema if exists test cascade');
        $pg->db->query('create schema test');
    }
    $pg->migrations->from_dir($self->home . '/sql');
    $pg->migrations->migrate();
    $self->helper( pg => sub { return $pg; } );

    # DB Schema
    my $schema = CF::Schema->connect({
        dsn      => $cfg->{db_dsn},
        user     => $cfg->{db_username},
        password => $cfg->{db_password},
    });

    if ( $cfg->{test} ) {
        $schema->storage->dbh->do("set search_path to test") ;
    }

    $self->helper( schema => sub { return $schema; } );

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

    $self->plugin('CF::Helpers::Core');
    $self->plugin('CF::Helpers::Auth');

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

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

                my $key = $c->req->headers->authorization;

                # moznost nepovinneho bez tokenu
                return $c->$cb() if $scopes->[0] && $scopes->[0] eq 'optional' && ! $key;

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

                $c->oauth_token($key);

                if (! $c->user ) {
                    return $c->$cb('Invalid user');
                }

                my $user = $c->schema->resultset('User')->find_or_create(
                    $c->user, { key => 'uuid'}
                );
                $user->set_secret();
                $user->update_roles($c->user_roles);

                $c->stash->{user}{id} = $user->id;

                return $c->$cb() if ! scalar @{ $scopes };

                ROLE:
                foreach my $role ( @{ $scopes } ) {
                    return $c->$cb() if $role eq '*';
                    return $c->$cb() if $c->user_roles->{ $role };
                }

                return $c->$cb('Insufficient permissions');
            }
        }
    });

    $self->defaults(
        openapi_cors_allowed_origins => ['*']
    );

    # Router
    my $r = $self->routes;
    $r->get('/')->to(cb => sub { shift->redirect_to('/api.html');});

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

1;