package Pcore::App::Controller::ExtJS::App;

use Pcore -role, -status;
use Pcore::Util::Text qw[mark_raw];
use Pcore::Util::Data qw[to_json];
use Pcore::App::API qw[:CONST];
use Pcore::Share::WWW;
use WWW::CDN;

with qw[Pcore::App::Controller::ExtJS];

requires qw[ext_class_viewport];

has extjs_ver                   => ( is => 'ro', isa => Str, default => $WWW::CDN::LATEST_VERION->{extjs} );
has extjs_default_theme_classic => ( is => 'ro', isa => Str, default => 'triton' );
has extjs_default_theme_modern  => ( is => 'ro', isa => Str, default => 'triton' );
has extjs_default_locale        => ( is => 'ro', isa => Str, default => 'en' );

around run => sub ( $orig, $self, $req ) {
    if ( $req->{path_tail} && $req->{path_tail} ne 'index.html' ) {

        # signin
        if ( $req->{path_tail} eq 'signin' ) {
            my $body = P->data->from_uri_query( $req->body->$* );

            $self->{app}->{api}->authenticate(
                $body->{username},
                $body->{password},
                sub ($auth) {

                    # authentication error
                    if ( !$auth ) {
                        $req->($auth)->finish;
                    }

                    # authenticated
                    else {

                        # create user session
                        $self->{app}->{api}->create_user_session(
                            $auth->{user_id},
                            sub ($session) {

                                # user session creation error
                                if ( !$session ) {
                                    $req->($session)->finish;
                                }

                                # user session created
                                else {
                                    my $res = status 200;

                                    $req->( $res, [ 'Set-Cookie' => "token=$session->{result}->{token}; Path=/; HttpOnly; SameSite=lax; Max-Age=" . ( 60 * 60 * 24 * 365 ) ], to_json $res )->finish;
                                }

                                return;
                            }
                        );
                    }

                    return;
                }
            );
        }

        # signout
        elsif ( $req->{path_tail} eq 'signout' ) {
            $req->authenticate(
                sub ($auth) {

                    # authentication error
                    if ( !$auth ) {
                        $req->( 303, [ Location => $self->path, 'Set-Cookie' => 'token=; Path=/; HttpOnly; Max-Age=0' ] )->finish;
                    }

                    # authenticated
                    else {

                        # session token
                        if ( $auth->{token_type} == $TOKEN_TYPE_USER_SESSION ) {

                            # remove user session
                            $self->{app}->{api}->remove_user_session(
                                $auth->{token_id},
                                sub ($res) {

                                    # session not removed
                                    if ($res) {
                                        $req->( 303, [ Location => $self->path, 'Set-Cookie' => 'token=; Path=/; HttpOnly; Max-Age=0' ] )->finish;
                                    }

                                    # session removed
                                    else {
                                        $req->( 303, [ Location => $self->path, 'Set-Cookie' => 'token=; Path=/; HttpOnly; Max-Age=0' ] )->finish;
                                    }

                                    return;
                                }
                            );
                        }

                        # not session token
                        else {
                            $req->( 303, [ Location => $self->path, 'Set-Cookie' => 'token=; Path=/; HttpOnly; Max-Age=0' ] )->finish;
                        }
                    }

                    return;
                }
            );
        }
        else {
            $self->$orig($req);
        }

        return;
    }

    my $resources = [];

    # FontAwesome
    push $resources->@*, WWW::CDN->fontawesome;

    # ExtJS framework
    my $devel     = $req->{env}->{QUERY_STRING} =~ /\bdevel\b/sm;
    my $ver       = $self->extjs_ver;
    my $framework = 'classic';

    my $extjs_resources;

    # get theme from query
    if ( $req->{env}->{QUERY_STRING} =~ /\btheme=([a-z-]+)/sm ) {
        my $theme = $1;

        $extjs_resources = WWW::CDN->extjs( $ver, $framework, $theme, $devel );
    }

    # fallback to the default theme
    if ( !$extjs_resources ) {
        my $theme = $framework eq 'classic' ? $self->extjs_default_theme_classic : $self->extjs_default_theme_modern;

        $extjs_resources = WWW::CDN->extjs( $ver, $framework, $theme, $devel );
    }

    push $resources->@*, $extjs_resources->@*;

    # ExtJS locale
    my $locale = $self->extjs_default_locale;

    push $resources->@*, WWW::CDN->extjs_locale( $ver, $framework, $locale, $devel );

    # ExtJS overrides
    # <script type="text/javascript" src="/static/sencha/ext/pcore/overrides.js"></script>

    my $loader_path = {
        q[*]                       => q[.],
        Ext                        => '/static/extjs/src/',
        'Ext.ux'                   => '/static/extjs/ux/',
        Pcore                      => '/static/extjs/pcore/',
        $self->{ext_app_namespace} => $self->{path},
    };

    my $data = {
        INDEX     => { title => 'Admin', },
        resources => $resources,
        ext       => {
            api_map        => undef,
            loader_path    => mark_raw( to_json( $loader_path, readable => $devel )->$* ),
            app_namespace  => $self->{ext_app_namespace},
            viewport_class => "$self->{ext_app_namespace}.Viewport",
        },
    };

    my $index = P->tmpl->render( 'sencha/index-extjs.html', $data );

    $req->( 200, [ 'Content-Type' => 'text/html; charset=UTF-8' ], $index )->finish;

    return;
};

1;
## -----SOURCE FILTER LOG BEGIN-----
##
## PerlCritic profile "pcore-script" policy violations:
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
## | Sev. | Lines                | Policy                                                                                                         |
## |======+======================+================================================================================================================|
## |    1 | 132                  | RegularExpressions::ProhibitEnumeratedClasses - Use named character classes ([a-z] vs. [[:lower:]])            |
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
##
## -----SOURCE FILTER LOG END-----
__END__
=pod

=encoding utf8

=head1 NAME

Pcore::App::Controller::ExtJS::App - ExtJS application HTTP controller

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 ATTRIBUTES

=head1 METHODS

=head1 SEE ALSO

=cut
