#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - scripts/koalitool                        opyright 2023 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package scripts::koalitool;

use cPstrict;

use Cpanel::Koality::Auth    ();
use Cpanel::Koality::User    ();
use Cpanel::Koality::Project ();

use Getopt::Long;

use Data::Dumper;

exit run(@ARGV) unless caller();

sub run {

    my @args = @_;
    my $opts = {};

    Getopt::Long::GetOptionsFromArray(
        \@args,
        'auth|a'                    => \$opts->{auth_user},
        'create|c'                  => \$opts->{create_user},
        'delete|del'                => \$opts->{delete_user},
        'disable-onboarding|dob'    => \$opts->{disable_onboarding},
        'dump|d'                    => \$opts->{dump_all},
        'email|e=s'                 => \$opts->{email},
        'get-project|gp'            => \$opts->{get_project},
        'get-subscription|gsub'     => \$opts->{get_subscription},
        'get-scores|gsco'           => \$opts->{get_scores},
        'get-system-id|gsi=s'       => \$opts->{system_type},
        'get-system-size-id|gssi=s' => \$opts->{system_size},
        'help|h'                    => \$opts->{help},
        'info|i'                    => \$opts->{get_user_info},
        'pass|p=s'                  => \$opts->{pass},
        'project-create|pc'         => \$opts->{project_create},
        'project-id|pi=i'           => \$opts->{project_id},
        'project-name|pn=s'         => \$opts->{project_name},
        'project-url|pu=s'          => \$opts->{project_url},
        'projects|gap'              => \$opts->{projects},
        'really|f'                  => \$opts->{really},
        'request|req'               => \$opts->{request},
        'method|met=s'              => \$opts->{method},
        'endpoint|end=s'            => \$opts->{endpoint},
        'payload|pay=s'             => \$opts->{payload},
        'set-locale|l=s'            => \$opts->{locale},
        'system-types|gst'          => \$opts->{system_types},
        'user|u=s'                  => \$opts->{user},
        'verify|v=s'                => \$opts->{code},
        'verbose'                   => \$opts->{verbose},
    );

    if ( !$opts->{user} ) {
        return help("Must specify a cPanel user with the '-u' flag.");
    }

    if    ( $opts->{help} )               { return help() }
    elsif ( $opts->{get_user_info} )      { get_user_info( $opts->{user} ) }
    elsif ( $opts->{dump_all} )           { dump_all($opts) }
    elsif ( $opts->{auth_user} )          { auth_user($opts) }
    elsif ( $opts->{create_user} )        { create_user($opts) }
    elsif ( $opts->{delete_user} )        { delete_user($opts) }
    elsif ( $opts->{code} )               { verify_code($opts) }
    elsif ( $opts->{project_create} )     { create_project($opts) }
    elsif ( $opts->{projects} )           { get_projects($opts) }
    elsif ( $opts->{get_project} )        { get_project($opts) }
    elsif ( $opts->{get_scores} )         { get_scores($opts) }
    elsif ( $opts->{request} )            { do_request($opts) }
    elsif ( $opts->{system_type} )        { get_system_id_for_type($opts) }
    elsif ( $opts->{system_types} )       { get_system_types($opts) }
    elsif ( $opts->{system_size} )        { get_system_size_id($opts) }
    elsif ( $opts->{get_subscription} )   { get_subscription($opts) }
    elsif ( $opts->{disable_onboarding} ) { disable_onboarding($opts) }
    else                                  { return help() }

    return 1;
}

sub help ( $str = '' ) {
    print "\n$str\n\n";

    my $help_message = <<'HELP';
This is a tool to work with the Koality backend.

Flags:

  --help               -h    : Display this help text.

  --user               -u    : The cPanel username of the account. Required.

  --info               -i    : Return the user information for the cPanel user.

  --dump               -d    : Dump the full user data return from Koality.

  --auth               -a    : Authenticate a user with the Koality backend.
                               Must have created the user and validated the email address.

  --verify             -v    : Pass the one-time code to validate the account.

  --system-types       -gst  : Get all system types.

  --get-subscription   -gsub : Retrieve subscription information.

  --disable-onboarding -dob  : Disable the onboarding wizard.

  --create             -c    : Create a new Koality user, must provide an email address.
      --email          -e    : The email address for the new Koality account. Required.
      --pass           -p    : The password for the new Koality account. Optional.
      --set-locale     -l    : Set the locale. Optional.

  --delete                   : Delete the Koality user.
      --really         -f    : Sanity check. Required.

  --project-create     -pc   : Create a new Koality project.
      --project-name   -pn   : The name of the new project. Required.
      --project-url    -pu   : The url to monitor. Required.

  --get-project        -gp   : Get a Koality Project
      --project-id     -pi   : The Koality project ID.

Examples:

  Create a new account:
    ./koalitool -u cpanel_user --create -e me@mail.com -p password

  Authenticate to get a session token:
    ./koalitool -u cpanel_user --auth

  Get existing user information:
    ./koalitool -u cpanel_user --info
HELP

    print "$help_message\n\n";
    return 1;
}

sub do_request ($opts) {
    die "Must provide an --endpoint and a --payload.\n" if !$opts->{endpoint} || !$opts->{payload};

    my $user = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} )->auth_session();

    require Cpanel::JSON;
    my $payload = Cpanel::JSON::Load( $opts->{payload} );

    $user->api->method( $opts->{method} // 'POST' );
    $user->api->base_url( $user->cluster_endpoint );
    $user->api->endpoint( $opts->{endpoint} );
    $user->api->payload( { access_token => $user->session_token, $payload->%* } );
    my $response = $user->api->run();
    print Dumper $response;

    return 1;
}

sub create_project ($opts) {

    help('Must define a project name and project url.') if !$opts->{project_name} || !$opts->{project_url};

    my $proj     = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    my $new_proj = $proj->create_project( { name => $opts->{project_name}, url => $opts->{project_url} } );

    print Dumper $new_proj;
    return 1;
}

sub get_user_info ($cpaneluser) {
    my $user = Cpanel::Koality::User->new( 'cpanel_username' => $cpaneluser );
    return _print_user_info( $cpaneluser, $user->user_config );
}

sub auth_user ($opts) {
    my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
    my $user = $auth->auth_session();
    return _print_user_info( $opts->{user}, $user->user_config );
}

sub create_user ($opts) {
    if ( $opts->{email} ) {
        my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
        if ( $opts->{'locale'} ) {
            warn 'WARNING: Locale string truncated to 2 characters' if length( $opts->{'locale'} ) > 2;
            $auth->locale( $opts->{'locale'} );
        }
        my $user = $auth->create_user( $opts->{email}, $opts->{pass} );
        return _print_user_info( $opts->{user}, $user->user_config );
    }
    else {
        return help('Must specify an email address with -e');
    }
}

sub verify_code ($opts) {
    if ( $opts->{'code'} ) {
        my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
        $auth->verify_code( $opts->{'code'} );
        return;
    }
    else {
        return help('Must specify a code with -v');
    }
}

sub delete_user ($opts) {
    if ( $opts->{'really'} ) {
        my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
        return Dumper $auth->delete_user();
    }
    else {
        return help('Must be sure you --really want to delete.');
    }
}

sub get_project ($opts) {
    help('Must define a project id.') if !$opts->{project_id};

    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper $projects->get_project_by_id( $opts->{project_id} );

    return 1;
}

sub get_projects ($opts) {
    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper [ $projects->get_all_projects() ];

    return 1;
}

sub get_system_id_for_type ($opts) {
    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper $projects->get_system_id_for_type( $opts->{system_type} );

    return 1;
}

sub get_system_types ($opts) {
    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper $projects->get_system_types();

    return 1;
}

sub get_scores ($opts) {
    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper $projects->get_all_scores( $opts->{verbose} );

    return 1;
}

sub get_system_size_id ($opts) {
    my $projects = Cpanel::Koality::Project->new( 'cpanel_username' => $opts->{user} );
    print Dumper $projects->get_system_size_id( $opts->{system_size} );

    return 1;
}

sub get_subscription ($opts) {
    my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
    my $user = $auth->auth_session();
    print Dumper $user->get_subscription();

    return 1;
}

sub disable_onboarding ($opts) {
    my $auth = Cpanel::Koality::Auth->new( 'cpanel_username' => $opts->{user} );
    my $user = $auth->auth_session();
    print Dumper $user->disable_onboarding();

    return 1;
}

sub _print_user_info ( $user, $config ) {
    printf "\nKoality User Information for cPanel user %s\n\n", $user;
    for my $key ( sort keys $config->%* ) {
        next if ( $key eq 'full' );
        $config->{$key} //= 'N/A';
        printf "%-20s: %s\n", $key, $config->{$key};
    }
    print "\n";
    return 1;
}

sub dump_all ($opts) {
    my $user = Cpanel::Koality::User->new( 'cpanel_username' => $opts->{user} );
    print Dumper $user->user_config;
    return 1;
}
