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

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

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

requires qw[ext_class_viewport];

const our $EXT_FRAMEWORK_CLASSIC => 1;
const our $EXT_FRAMEWORK_MODERN  => 2;

const our $EXT_FRAMEWORK_NAME => {
    $EXT_FRAMEWORK_CLASSIC => 'classic',
    $EXT_FRAMEWORK_MODERN  => 'modern',
};

const our $EXT_THEME_ARIA          => 1;
const our $EXT_THEME_CLASSIC       => 2;
const our $EXT_THEME_CRISP         => 3;
const our $EXT_THEME_CRISP_TOUCH   => 4;
const our $EXT_THEME_GRAY          => 5;
const our $EXT_THEME_NEPTUNE       => 6;
const our $EXT_THEME_NEPTUNE_TOUCH => 7;
const our $EXT_THEME_TRITON        => 8;
const our $EXT_THEME_CUPERTINO     => 9;
const our $EXT_THEME_IOS           => 10;
const our $EXT_THEME_MATERIAL      => 11;
const our $EXT_THEME_MOUNTAINVIEW  => 12;
const our $EXT_THEME_WINDOWS       => 13;

const our $EXT_FRAMEWORK_CLASSIC_THEME => {
    $EXT_THEME_ARIA          => 'aria',
    $EXT_THEME_CLASSIC       => 'classic',
    $EXT_THEME_CRISP         => 'crisp',
    $EXT_THEME_CRISP_TOUCH   => 'crisp-touch',
    $EXT_THEME_GRAY          => 'gray',
    $EXT_THEME_NEPTUNE       => 'neptune',
    $EXT_THEME_NEPTUNE_TOUCH => 'neptune-toouch',
    $EXT_THEME_TRITON        => 'triton',
};

const our $EXT_FRAMEWORK_MODERN_THEME => {
    $EXT_THEME_CUPERTINO    => 'cupertino',
    $EXT_THEME_IOS          => 'ios',
    $EXT_THEME_MATERIAL     => 'material',
    $EXT_THEME_MOUNTAINVIEW => 'mountainview',
    $EXT_THEME_WINDOWS      => 'windows',
    $EXT_THEME_NEPTUNE      => 'neptune',
    $EXT_THEME_TRITON       => 'triton',
};

has framework => ( is => 'ro', isa => Enum [ $EXT_FRAMEWORK_CLASSIC, $EXT_FRAMEWORK_MODERN ], default => $EXT_FRAMEWORK_CLASSIC );
has classic_theme => ( is => 'ro', isa => Enum [ keys $EXT_FRAMEWORK_CLASSIC_THEME->%* ], default => $EXT_THEME_TRITON );
has modern_theme  => ( is => 'ro', isa => Enum [ keys $EXT_FRAMEWORK_MODERN_THEME->%* ],  default => $EXT_THEME_MATERIAL );
has 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 $devel = 1;

    my $ext_framework_name = $self->framework == $EXT_FRAMEWORK_MODERN ? 'modern-' : q[];
    my $framework          = $EXT_FRAMEWORK_NAME->{ $self->framework };
    my $debug              = $devel ? '-debug' : q[];
    my $theme              = $self->framework == $EXT_FRAMEWORK_MODERN ? $EXT_FRAMEWORK_MODERN_THEME->{ $self->modern_theme } : $EXT_FRAMEWORK_CLASSIC_THEME->{ $self->classic_theme };

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

    # CloudFlare CDN
    # https://cdnjs.com/libraries/extjs

    my $extjs_ver       = '6.2.0';
    my $extjs_framework = 'classic';

    my $resources = {
        INDEX => { title => 'Admin', },
        ext   => {
            extjs          => "https://cdnjs.cloudflare.com/ajax/libs/extjs/$extjs_ver/ext-all${debug}.js",
            extjs_ux       => "https://cdnjs.cloudflare.com/ajax/libs/extjs/$extjs_ver/packages/ux/$extjs_framework/ux.js",
            theme_css      => "https://cdnjs.cloudflare.com/ajax/libs/extjs/$extjs_ver/$extjs_framework/theme-${theme}/resources/theme-${theme}-all${debug}.css",
            theme_js       => "https://cdnjs.cloudflare.com/ajax/libs/extjs/$extjs_ver/$extjs_framework/theme-${theme}/theme-${theme}${debug}.js",
            locale_js      => "https://cdnjs.cloudflare.com/ajax/libs/extjs/$extjs_ver/$extjs_framework/locale/locale-@{[$self->locale]}${debug}.js",
            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 $resources = {
    #     INDEX => { title => 'Admin', },
    #     ext   => {
    #         extjs          => "/static/sencha/ext/build/ext-${ext_framework_name}all${debug}.js",
    #         extjs_ux       => "/static/sencha/ext/build/packages/ux/$framework/ux${debug}.js",
    #         theme_css      => "/static/sencha/ext/build/$framework/theme-$theme/resources/theme-$theme-all${debug}.css",
    #         theme_js       => "/static/sencha/ext/build/$framework/theme-$theme/theme-$theme${debug}.js",
    #         locale_js      => "/static/sencha/ext/build/$framework/locale/locale-@{[$self->locale]}${debug}.js",
    #         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', $resources );

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

    return;
};

1;
__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
