
#                                      Copyright 2024 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package Whostmgr::360Monitoring::Auth;

use Moo;
use cPstrict;
extends 'Whostmgr::360Monitoring::Base';

use Whostmgr::360Monitoring::User     ();
use Whostmgr::360Monitoring::Validate ();
use Cpanel::JSON                      ();
use Cpanel::Rand::Get                 ();

# instead of Cpanel::Imports so we can use `locale` as an API param
use Cpanel::Locale;
my $cp_locale = Cpanel::Locale->get_handle;

=head1 MODULE

C<Whostmgr::360Monitoring::Auth>

=head1 DESCRIPTION

C<Whostmgr::360Monitoring::Auth> is a class that provides methods for tasks relating to creating or authenticating a 360Monitoring user.

=cut

=head2 locale - string

The locale of the activation email sent during new user sign up.

=cut

has 'locale' => (
    is      => 'rw',
    isa     => \&Whostmgr::360Monitoring::Validate::valid_locale,
    default => sub ($self) {
        require Cpanel::Locale::Utils::User;
        my $locale = Cpanel::Locale::Utils::User::get_user_locale( $self->username );
        return 'en' if !$locale;

        $locale = substr $locale, 0, 2;
        return $locale;
    },
);

sub _get_api_key ($self) {
    my $user = Whostmgr::360Monitoring::User->new( username => $self->username, );
    return $user->api_key;
}

=head1 METHODS

=head2 create_user( password )

Create a new 360Monitoring user and associate it with a cPanel account.

=head3 ARGUMENTS

=over

=item password - string

A password for authentication. If one is not provided, a pseudorandom one is generated.

=back

=head3 RETURNS

An instance of C<Whostmgr::360Monitoring::User> created using the provided details as well as the newly acquired app token.

=head3 EXAMPLES

my $auth = Whostmgr::360Monitoring::Auth->new();

my $user = eval { $auth->create_user( $email, $pass ) };

=cut

sub create_user ( $self, $password = '' ) {
    if ( $self->_get_api_key() ) {
        die $cp_locale->maketext("This [asis,cPanel] user already has an associated [asis,Server Monitoring] account.") . "\n";
    }

    if ( !$password ) {
        $password = Cpanel::Rand::Get::getranddata( 64, [ 0 .. 9, 'a' .. 'z', 'A' .. 'Z', '$', '%', '+', '!', '^', '*' ] );
    }

    require Cpanel::Rand::Get;
    my $rand = Cpanel::Rand::Get::getranddata( 32, [ 0 .. 9, 'a' .. 'f' ] );

    $self->api->base_url( $self->app360_url );
    $self->api->method('POST');
    $self->api->endpoint('user/create');
    $self->api->payload(
        {
            password => $password,
            consent  => Cpanel::JSON::true(),

            # For analytics and consent identification
            companyId => $self->company_id,
            serverId  => $self->server_id,
            userId    => $self->username,
        }
    );

    my $response = $self->api->run();
    my $ret      = Cpanel::JSON::Load($response);

    my $user = Whostmgr::360Monitoring::User->new(
        username => $self->username,
        user_id  => $ret->{userId},
        api_key  => $ret->{apiKey},
    );
    $user->save_user_info();
    return $user;
}

=head2 auth_session()

Generate an authenticated session for the 360Monitoring user associated with the current cPanel account.

=head3 ARGUMENTS

=over

=item None.

=back

=head3 RETURNS

An instance of C<Whostmgr::360Monitoring::User> authenticated using the details saved during user creation.

=head3 EXAMPLES

my $auth = Whostmgr::360Monitoring::Auth->new();

my $user = eval { $auth->auth_session() };

=cut

sub auth_session ($self) {

    my $user = $self->get_user();
    $self->get_session_tokens($user);

    return $user;
}

=head2 get_user()

Retrieves a users information from the koality backend.

=head3 ARGUMENTS

=over

=item None.

=back

=head3 RETURNS

An instance of C<Whostmgr::360Monitoring::User> authenticated using the details saved during user creation.

=cut

sub get_user ($self) {

    $self->api->base_url( $self->auth_url );
    $self->api->method('POST');
    $self->api->endpoint('auth/session');

    my $token = $self->_get_api_kiey() // die $cp_locale->maketext( "No token found for user [_1].", $self->cpanel_username ) . "\n";
    $self->api->payload( { sessionToken => $token } );
    my $response = $self->api->run();

    my %user_info = (
        app_token        => $token,
        auth_token       => $response->{data}{token},
        cluster_endpoint => $response->{data}{companies}[0]{cluster}{apiEndpoint} . "v1/",
        master_user_id   => $response->{data}{user}{id},
        enabled          => $response->{data}{user}{enabled},
        uuid             => $response->{data}{user}{userName},
    );

    my $user = Whostmgr::360Monitoring::User->new( cpanel_username => $self->cpanel_username, %user_info );
    $user->save_user_info();

    return $user;
}

=head2 get_session_tokens()

Retrieves a users session related information from the koality backend. The information is
updated in Whostmgr in C<Whostmgr::360Monitoring::User> properties and persisted to the file system.

=head3 ARGUMENTS

=over

=item None.

=back

=head3 RETURNS

An instance of C<Whostmgrs::360Monitoring::User> authenticated using the details saved during user creation.

=cut

sub get_session_tokens ( $self, $user ) {

    my $url        = $user->cluster_endpoint // die $cp_locale->maketext("No [asis,Server Monitoring] server found. You must authenticate first.");
    my $id         = $user->master_user_id   // die $cp_locale->maketext("No [asis,Server Monitoring] user ID found. You must authenticate first.");
    my $auth_token = $user->auth_token       // die $cp_locale->maketext("No [asis,Server Monitoring] API authentication token found. You must authenticate first.");

    $self->api->method('POST');
    $self->api->base_url($url);
    $self->api->endpoint( "auth/tokens/token/" . $id );
    $self->api->auth_token($auth_token);
    $self->api->payload( { access_token => $auth_token } );
    my $response = $self->api->run();

    $user->session_token( $response->{data}{token} );
    $user->refresh_token( $response->{data}{refresh_token} );
    $user->user_id( $response->{data}{user}{id} );

    $user->save_user_info( $response->{data} );

    return $user;
}

=head2 verify_code()

Verifies a code that was sent to the user via email.

=head3 ARGUMENTS

=over

=item code - String - Required

The string to verify.

=back

=head3 RETURNS

Whether or not the code was verified successfully.

=over

=item status - bool

Returns 1 when the code is verified.

Returns 0 when the code fails to verify.

=back

=head3 EXAMPLES

my $auth = Cpanel::360Monitoring::Auth->new();

$auth->verify_code('1234');

=cut

sub verify_code ( $self, $code ) {

    my $user = $self->get_user();

    $self->api->base_url( $user->auth_url );
    $self->api->method('POST');
    $self->api->endpoint('user/activate/code');
    $self->api->payload(
        {
            activation_code => $code,
            user            => $user->master_user_id
        }
    );

    my $response = $self->api->run();

    return defined $response->{status} && $response->{status} eq 'success' ? 1 : 0;
}

=head2 send_activation_email()

Triggers the send of a new user activation email.

=head3 ARGUMENTS

None.

=head3 RETURNS

Whether or not the request to send the email was successful.

=over

=item status - bool

Returns 1 when the email request was successful.

Returns 0 when the email request was not successful.

=back

=head3 EXAMPLES

my $auth = Cpanel::360Monitoring::Auth->new();

$auth->send_activation_email();

=cut

sub send_activation_email ($self) {

    my $user = $self->get_user();

    $self->api->base_url( $user->auth_url );
    $self->api->method('POST');
    $self->api->endpoint('user/resend-activation');
    $self->api->payload( { user => $user->master_user_id } );

    my $response = $self->api->run();

    return defined $response->{status} && $response->{status} eq 'success' ? 1 : 0;
}

1;
