#!/usr/local/cpanel/3rdparty/bin/perl -w

# cpanel - t/medium/Cpanel-Koality-User.t          Copyright 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 t::medium::Cpanel::Koality::User;

use cPstrict;
use Test::Cpanel::Policy;

use Test2::V0;
use Test2::Plugin::NoWarnings;
use Test2::Tools::Exception;

use Test::MockModule          ();
use Test::MockObject::Extends ();
use Test::MockFile            ();
use File::Temp                ();
use Cpanel::JSON              ();

use Cpanel::Koality::User ();

use base qw(Test::Class);

my $mock_stage_file = Test::MockFile->file('/var/cpanel/use_koality_stage');
my $mock_safefile   = Test::MockFile->file( '/var/cpanel/safefile_verbose',     '1' );
my $mock_errorlog   = Test::MockFile->file( '/usr/local/cpanel/logs/error_log', {} );

my $mock_privs = Test::MockModule->new('Cpanel::AccessIds::ReducedPrivileges');
$mock_privs->redefine( 'new' => sub { return 1 } );

my $mock_validate = Test::MockModule->new('Cpanel::Koality::Validate');
$mock_validate->redefine( 'valid_api_object' => sub { return 1 } );

my $mock_username = Test::MockModule->new('Cpanel::Validate::Username');
$mock_username->redefine( 'user_exists_or_die' => sub { return 1 } );

my $homedir      = File::Temp->newdir();
my $mock_pwcache = Test::MockModule->new('Cpanel::PwCache');
$mock_pwcache->redefine( 'gethomedir' => sub { return $homedir } );

my $mock_fileopts = Test::MockModule->new('Cpanel::Koality::User');
$mock_fileopts->redefine( '_ensure_conf_dir' => sub ($self) { return mkdir( $homedir . '/.koality' ) } );

my $mock_perms = Test::MockModule->new('Cpanel::Transaction::File::Base');
$mock_perms->redefine( '_set_permissions' => sub { return 1 } );

my $mock_companyid = Test::MockModule->new('Cpanel::License::CompanyID');
$mock_companyid->redefine( 'get_company_id' => sub { return '42' } );

my $mock_serverid = Test::MockModule->new('Cpanel::Plugins::ServerId');
$mock_serverid->redefine( 'get_server_id' => sub { return '101010' } );

my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
$mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );

my $expected_api_response = {};

__PACKAGE__->new()->runtests() if !caller;

sub test_constructor : Tests(11) {

    my $tests = {
        _conf_dir        => '/../../foo',
        _conf_file       => '/../',
        user_config      => 'This is invalid',
        koality_username => '@foo@bar@.com@',
        auth_token       => '!token!',
        session_token    => '@token@',
        app_token        => '%token%',
        refresh_token    => '&token&',
        cluster_endpoint => 'domain.com',
        user_id          => 'abcd',
        enabled          => '',
    };

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );

    foreach my $test ( sort keys $tests->%* ) {
        ok( dies { Cpanel::Koality::User->new( $test => $tests->{$test} ) }, "new: Dies with invalid $test" );
    }

    return;
}

sub test_save_user_info : Tests(10) {

    local $Cpanel::user = 'root';

    my $api = _setup_api_mock();

    my $expected_info = {
        koality_username => 'my@email.com',
        auth_token       => 'auth_1234',
        app_token        => 'app_1234',
        cluster_endpoint => 'https://api.com/',
        user_id          => '1234',
        refresh_token    => 'refresh_1234',
        session_token    => 'session_1234',
        uuid             => '1234-1234-1234-1234',
        api              => $api,
    };

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );
    my $user = Cpanel::Koality::User->new($expected_info);

    my $additional_info = { this => 'is some', additional => 'information' };

    ok( lives { $user->save_user_info($additional_info) }, 'save_user_info: Saves config successfully.' );
    my $on_disk;
    ok( lives { $on_disk = Cpanel::JSON::LoadFile( $user->_conf_file ) }, 'save_user_info: JSON on disk is valid.' );

    foreach my $info ( keys $expected_info->%* ) {
        next if $info eq 'api';
        is( $on_disk->{$info}, $expected_info->{$info}, "save_user_info: The expected value for $info found in the user's config" );
    }

    return;
}

sub test_get_subscription : Tests(2) {

    local $Cpanel::user = 'root';

    my $api = _setup_api_mock();

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );
    my $user = Cpanel::Koality::User->new( api => $api );
    ok( dies { $user->get_subscription() }, 'get_subscription: Dies if we do not have a company id.' );

    $user->user_config( { full => { user => { company => { id => '1234' } } } } );
    $expected_api_response = { data => 'mysub' };
    is( $user->get_subscription(), 'mysub', 'get_subscription: Got the expected subscription.' );

    return;
}

sub test_disable_onboarding : Tests(4) {

    local $Cpanel::user = 'root';

    my $api = _setup_api_mock();

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );
    my $user = Cpanel::Koality::User->new( api => $api, );

    $user->user_config( { master_user_id => '98998', auth_token => 'auth_token_1234' } );
    $expected_api_response = { data => 'ok' };
    $user->disable_onboarding();
    is( $user->api->method,     'PUT',                                         'disable_onboarding: Got correct method.' );
    is( $user->api->payload,    { key => 'welcomeFinished', value => 'true' }, 'disable_onboarding: Got correct payload.' );
    is( $user->api->auth_token, 'auth_token_1234',                             'disable_onboarding: Got correct auth_token.' );
    like( $user->api->endpoint, qr/98998$/, 'disable_onboarding: Got correct auth_token.' );

    return;
}

sub test_reset_config : Tests(3) {

    local $Cpanel::user = 'root';

    my $api = _setup_api_mock();

    my $mock_locale = Test::MockModule->new('Cpanel::Locale::Utils::User');
    $mock_locale->redefine( 'get_user_locale' => sub { return 'en' } );
    my $user = Cpanel::Koality::User->new( api => $api );

    $user->user_config( { app_token => 'old', koality_username => 'old@old.com' } );
    $user->save_user_info();

    $user = $user->reset_config();

    isnt( $user->app_token, 'old', 'reset_config: old values no longer exist.' );
    is( $user->user_config, {}, 'reset_config: user_config is empty.' );

    my $mock_home = Test::MockFile->dir($homedir);
    ok( $user->reset_config(), 'reset_config: returns success when no config file exists.' );

    return;
}

sub _setup_api_mock {

    my $api = Cpanel::Koality::ApiClient->new( 'http_client' => sub { } );
    $api = Test::MockObject::Extends->new($api);

    $api->mock( 'run'         => sub { return $expected_api_response } );
    $api->mock( 'http_client' => sub { return 1 } );

    return $api;
}
1;
