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

# cpanel - t/medium/Cpanel-Sitejet-Connector.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::Sitejet::Connector;

use cPstrict;

use Test2::V0 -no_utf8 => 1;
use Test2::Tools::Explain;
use Test2::Plugin::NoWarnings;
use Test2::Tools::Exception qw/dies/;

use Test::MockFile;
use Test::MockObject;
use Test::MockTime;
use Test::Warn;

use Try::Tiny;

use Test::Cpanel::Policy;

# must go below T:C:Policy
use Mock::Cpanel::Logger;

use parent qw(
  Cpanel::TestObj
);

use Cpanel();

use Cpanel::Sitejet::Connector ();

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

#----------------------------------------------------------------------

#e.g., num_method_tests()
sub new ( $class, @args ) {
    my $self = $class->SUPER::new(@args);
    return $self;
}

#e.g., set environs before running tests
sub runtests ( $self, @args ) {
    $self->{'mock_cpuser_file_DNE'} = Test::MockFile->file('/var/cpanel/users/user_name');
    $self->{'mock_log_file'}        = Test::MockFile->file( '/usr/local/cpanel/logs/error_log',     'fake content' );
    $self->{'mock_cache_file'}      = Test::MockFile->file( '/var/cpanel/userdata/test_user/cache', 'fake content' );
    return $self->SUPER::runtests(@args);
}

sub test__accountExists : Tests(2) ($self) {
    my $case = 0;

    my @mocks = (
        $self->mock_subs(
            'Cpanel::Config::LoadCpUserFile::loadcpuserfile' => sub {
                if ( shift eq 'happyuser' ) {
                    return { SITEJET_API_TOKEN => '7a0596f61f5070543bcb27a8c6d37083' };
                }
                else {
                    return { NOTHING_HERE => '' };
                }
            },
        )
    );

    $case++;
    $Cpanel::user = "happyuser";
    my $result = Cpanel::Sitejet::Connector::accountExists();
    is( $result, 1, "test_accountExists Valid case$case : $Cpanel::user" );

    $case++;
    $Cpanel::user = 'unhappyuser';
    $result       = Cpanel::Sitejet::Connector::accountExists();
    is( $result, 0, "test_accountExists Invalid case$case : $Cpanel::user" );

    return;
}

sub test__cp_load_sitejet_metadata : Tests(2) ($self) {
    my $mocks = $self->_get_mocks();
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my @mocks     = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; }, ) );
    my $connector = Cpanel::Sitejet::Connector->new();

    my $metadata = $connector->cp_load_sitejet_metadata( $mocks->{'domain'} );

    ref_ok( $metadata, 'HASH', "test__cp_load_sitejet_metadata returns the JSON hash as expected." );
    is( $metadata->{'domain'}, $mocks->{'domain'}, "test__cp_load_sitejet_metadata returns the expected domain $mocks->{'domain'} as expected." );

    return;
}

sub test_request : Tests(4) ($self) {

    my @ua_inputs;
    my @logged;
    my @mocks = (
        $self->mock_subs(
            'LWP::UserAgent::get' => sub {
                return HTTP::Response->new(200);
            },
            'LWP::UserAgent::post' => sub {
                return HTTP::Response->new(200);
            },
            'Cpanel::Sitejet::Connector::cp_read_json' => sub {
                return {};
            }
        )
    );

    my $url     = 'http://1fb11c-5f2c7.preview.sitehub.io/';
    my $data_ar = [
        {
            'api_token' => '7a0596f61f5070543bcb27a8c6d37083',
            'method'    => 'get',
            'endpoint'  => '/v1/templates'
        },
        {
            'api_token' => '7a0596f61f5070543bcb27a8c6d37083',
            'method'    => 'post',
            'endpoint'  => '/website/1234/template/1234'
        },
        {
            'method'   => 'post',
            'endpoint' => '/cpanel/account',
            'data'     => { license => 'abcd' }
        },
    ];
    foreach my $case (@$data_ar) {
        my $resp = Cpanel::Sitejet::Connector->request( $case->{method}, $case->{endpoint}, $case->{api_token}, $case->{data} );
        ref_ok( $resp, 'HASH', "test_request returns hashref as expected" );

    }

    @mocks = ();
    @mocks = (
        $self->mock_subs(
            'LWP::UserAgent::get' => sub {
                return HTTP::Response->new(404);
            },
            'Cpanel::Exception::create' => sub {
                return die 'The API call failed with error code';
            }
        )
    );
    like(
        dies {
            my $got_content = Cpanel::Sitejet::Connector->request( 'get', '/v1/templates', '7a0596f61f5070543bcb27a8c6d37083' );
        },
        qr/The API call failed with error code/,
        "Got expected exception during failure"
    );

    return;
}

sub test_cp_getPreviewUrlPart : Tests(1) ($self) {

    local $Cpanel::homedir = '/home/example';
    my @mocks     = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; } ) );
    my $conn_obj  = Cpanel::Sitejet::Connector->new();
    my $websiteId = "390673";
    my $result    = $conn_obj->cp_getPreviewUrlPart($websiteId);
    is( $result, "/website/$websiteId/previewurl", "test_cp_getPreviewUrlPart Valid : $websiteId" );

    return;
}

sub test_cp_getPreviewUrl : Tests(1) ($self) {

    local $Cpanel::homedir = '/home/example';
    my @mocks     = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; } ) );
    my $conn_obj  = Cpanel::Sitejet::Connector->new();
    my $websiteId = "390673";
    my $result    = $conn_obj->cp_getPreviewUrl($websiteId);
    is( $result, "https://api.sitehub.io/website/$websiteId/previewurl", "test_cp_getPreviewUrl Valid : $websiteId" );

    return;
}

sub test_cp_write_json : Tests(1) ($self) {

    my $user = 'example';
    local $Cpanel::homedir = "/home/$user";
    my $file      = "$Cpanel::homedir/.cpanel/sitejet/mi.com";
    my $mock_file = Test::MockFile->file( $file, '' );
    my @mocks     = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
            'Cpanel::FileUtils::Write::overwrite'              => 1,
        )
    );
    my $data = {
        'templateId'    => '379435',
        'domain'        => 'mi.com',
        'document_root' => '/home/mock/public_html',
        'company'       => 'dump_mock_json_company'
    };
    my $conn_obj = Cpanel::Sitejet::Connector->new();
    my $result   = $conn_obj->cp_write_json( $file, $data );
    is( $result, 1, "test_cp_write_json Valid : $file" );

    return;
}

sub test_cp_update_logo : Tests(38) ($self) {
    my $user   = 'example';
    my $domain = "$user.test";
    local $Cpanel::homedir = "/home/$user";
    my $light_svg  = 'aVeryLongStringWith+s';
    my $dark_svg   = $light_svg;
    my $image_type = 'data:image/svg+xml;base64,';

    my @cases = (
        {
            'name'            => 'all values agree, so no update needed',
            'exp_zz_light_bg' => $image_type . $light_svg,
            'exp_zz_dark_bg'  => $image_type . $dark_svg,
            'exp_ret_light'   => $image_type . $light_svg,
            'exp_ret_dark'    => $image_type . $dark_svg,
            'exp_update'      => 0,
        },
        {
            'name'            => 'update is needed because local images are different/wrong',
            'exp_zz_light_bg' => "I'm sooo wrong",
            'exp_zz_dark_bg'  => "This isn't even an image",
            'exp_ret_light'   => $image_type . $light_svg,
            'exp_ret_dark'    => $image_type . $dark_svg,
            'exp_update'      => 1,
        },
        {
            'name'            => 'update is needed because local images are missing type',
            'exp_zz_light_bg' => $light_svg,
            'exp_zz_dark_bg'  => $dark_svg,
            'exp_ret_light'   => $image_type . $light_svg,
            'exp_ret_dark'    => $image_type . $dark_svg,
            'exp_update'      => 1,
        },
        {
            'name'            => 'update is needed because local images are empty',
            'exp_zz_light_bg' => '',
            'exp_zz_dark_bg'  => '',
            'exp_ret_light'   => $image_type . $light_svg,
            'exp_ret_dark'    => $image_type . $dark_svg,
            'exp_update'      => 1,
        },
        {
            'name'          => 'update is needed because no images saved in local metadata',
            'exp_ret_light' => $image_type . $light_svg,
            'exp_ret_dark'  => $image_type . $dark_svg,
            'exp_update'    => 1,
        },
        {
            'name'            => "update is not needed because of Sitejet problem (empty), but this doesn't die",
            'exp_zz_light_bg' => $image_type . $light_svg,
            'exp_zz_dark_bg'  => $image_type . $dark_svg,
            'exp_ret_light'   => '',
            'exp_ret_dark'    => '',
            'exp_update'      => 0,
        },
        {
            'name'            => "update is not needed because of Sitejet problem (undef), but this doesn't die",
            'exp_zz_light_bg' => $image_type . $light_svg,
            'exp_zz_dark_bg'  => $image_type . $dark_svg,
            'exp_update'      => 0,
        },
        {
            'name'            => 'update is needed for only image',
            'exp_zz_light_bg' => $image_type . $light_svg,
            'exp_zz_dark_bg'  => '',
            'exp_ret_light'   => $image_type . $light_svg,
            'exp_ret_dark'    => $image_type . $dark_svg,
            'exp_update'      => 1,
        },
    );

    for my $case (@cases) {
        my $case_name = $case->{name};
        my $exp_token = '7a0596f61f5070543bcb27a8c6d37083';
        my $got_domain;
        my ( $req_self, $got_post, $got_endpoint, $got_token, $got_data_hr );
        my ( $got_self, $got_domain_2, $got_data_hr_2 );

        my $sj_metadata_json = {
            'company'          => $user,
            'cpanelDomainGUID' => $domain,
            'domain'           => $domain,
            'fullcms'          => 1,
            'language'         => 'en',
            'templateId'       => '371888',
            'websiteId'        => 400075,
            'zz_light_bg'      => $case->{exp_zz_light_bg},
            'zz_dark_bg'       => $case->{exp_zz_dark_bg},
        };

        my @mocks = (
            $self->mock_subs(
                'Cpanel::Sitejet::Connector::loadApiKey' => sub {
                    return $exp_token;
                },
                'Cpanel::Sitejet::Connector::_check_domain_config'     => sub { return; },
                'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
                    $got_domain = shift;
                    return $sj_metadata_json;
                },
                'Cpanel::Sitejet::Connector::_get_default_cPanel_blob' => $light_svg,
                'Cpanel::Sitejet::Connector::request'                  => sub {
                    ( $req_self, $got_post, $got_endpoint, $got_token, $got_data_hr ) = @_;
                    my $ret_hr = {
                        'partner' => {
                            'editorLogoFileLight' => undef,
                            'editorLogoFileDark'  => undef,
                            'editorLogoLight'     => $case->{exp_ret_light},
                            'editorLogoDark'      => $case->{exp_ret_dark},
                        },
                    };
                    return $ret_hr;
                },
                'Cpanel::Sitejet::Connector::cp_update_sitejet_metadata' => sub {
                    ( $got_self, $got_domain_2, $got_data_hr_2 ) = @_;
                    return 1;
                },
                'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
                'Cpanel::FileUtils::Write::overwrite'              => 1,
            ),
        );

        my $conn_obj = Cpanel::Sitejet::Connector->new();
        my $ret_test = $conn_obj->cp_update_logo($domain);

        if ( $case->{exp_update} ) {
            is( $got_post,     'post',     "cp_update_logo - request got post when $case_name" );
            is( $got_endpoint, '/account', "cp_update_logo - request got endpoint when $case_name" );
            is( $got_token,    $exp_token, "cp_update_logo - request got proper token when $case_name" );
            is(
                $got_data_hr,
                {
                    'LogoDark'  => $case->{exp_ret_light},
                    'LogoLight' => $case->{exp_ret_dark},
                },
                "cp_update_logo - request got proper data_hr when $case_name"
            );
            is( $got_domain_2, $domain, "cp_update_logo - cp_update_sitejet_metadata got proper domain when $case_name" );
            is(
                $got_data_hr_2,
                {
                    'zz_dark_bg'  => $case->{exp_ret_light},
                    'zz_light_bg' => $case->{exp_ret_dark},
                },
                "cp_update_logo - cp_update_sitejet_metadata got proper data_hr when $case_name"
            );
        }

        is( $ret_test, 1, "cp_update_logo - sub exited with 1 when $case_name" );
    }

    return;
}

sub test_cp_load_all_sitejet_domains_metadata : Tests(2) ($self) {
    my $mocks = $self->_get_mocks();
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my @mocks = (
        $self->mock_subs(
            'Cpanel::DomainLookup::DocRoot::getdocroots' => sub {
                return { $mocks->{'domain'} => '/home/rubberduck/public_html' };
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    my $connector = Cpanel::Sitejet::Connector->new();

    my $metadata_href = $connector->cp_load_all_sitejet_domains_metadata();

    ref_ok( $metadata_href, 'HASH', "test_cp_load_all_sitejet_domains_metadata returns array as expected." );
    is( ( keys %{$metadata_href} )[0], $mocks->{'domain'}, "test_cp_load_all_sitejet_domains_metadata returns domain $mocks->{'domain'} as expected." );

    return;
}

sub test_cp_list_all_domain_sitebuilders : Tests(4) ($self) {
    my $mocks = $self->_get_mocks();
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my @mocks = (
        $self->mock_subs(
            'Cpanel::DomainLookup::DocRoot::getdocroots' => sub {
                return { $mocks->{'domain'} => '/home/rubberduck/public_html' };
            },
            'Cpanel::API::execute_or_die' => sub {
                my $result_obj = bless(
                    {
                        'status'        => 1,
                        'warnings'      => undef,
                        'messages'      => undef,
                        '_done_sorts'   => [],
                        '_done_filters' => [],
                        'metadata'      => {},

                        #'errors'           => undef,
                        '_done_pagination' => undef,
                        '_total_results'   => undef,
                        'data'             => $mocks->{'data'}
                    },
                    'Cpanel::Result',
                );
                return $result_obj;
            },
            'Cpanel::API::_verify_persona'                     => 1,
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    my $connector = Cpanel::Sitejet::Connector->new();

    my $output = $connector->cp_list_all_domain_sitebuilders( $mocks->{'domain'} );

    my $expected_output = {
        $mocks->{'domain'} => {
            'has_sitejet_published'  => 1,
            'is_sitejet'             => 1,
            'has_sitejet_templateId' => 1,
            'has_sitejet_website'    => 1
        }
    };
    ref_ok( $output, 'HASH', "test_cp_load_all_sitejet_domains_metadata returns hash as expected." );
    is( $output, $expected_output, "test_cp_list_all_domain_sitebuilders returns expected data." );

    # Do not provide an argument
    $output = $connector->cp_list_all_domain_sitebuilders();

    ref_ok( $output, 'HASH', "test_cp_load_all_sitejet_domains_metadata returns hash as expected when no domain is passed as an argument." );
    is( $output, $expected_output, "test_cp_list_all_domain_sitebuilders returns expected data when no domain is passed as an argument." );

    return;
}

sub test_cp_update_sitejet_metadata : Tests(1) ($self) {
    my $mocks = $self->_get_mocks();
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
            'Umask::Local::new'                                => 1,
            'Cpanel::SafeDir::MK::safemkdir_or_die'            => 1,
            'Cpanel::FileUtils::Write::overwrite'              => 1,
        )
    );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $data      = { 'write' => 'dummy_data' };
    my $connector = Cpanel::Sitejet::Connector->new();

    my $result = $connector->cp_update_sitejet_metadata( $mocks->{'domain'}, $data );

    is( $result, 1, "test_cp_update_sitejet_metadata adds data as expected." );

}

sub test_createWebsite : Tests(3) ($self) {
    my $user = 'dwight';
    local $Cpanel::homedir = "/home/$user";
    my @args;
    my %website_info = (
        'domain'    => 'theoffice.tld',
        'company'   => 'dundermifflin limited',
        'title'     => 'Assistant to the regional manager',
        'firstname' => 'Dwight',
        'lastname'  => 'schrute'
    );
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::loadApiKey'      => '7a0596f61f5070543bcb27a8c6d37083',
            'Cpanel::Sitejet::Publish::get_document_root' => "$Cpanel::homedir/public_html",
            'Cpanel::Sitejet::Connector::request'         => sub {
                @args = @_;
                return { 'websiteId' => 12345 };
            },
            'Cpanel::Sitejet::Connector::storeWebsiteId' => sub {
                return 1;
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    my $connector = Cpanel::Sitejet::Connector->new();

    my $web_id = $connector->createWebsite( \%website_info );

    is( $web_id,  12345,      "test_createWebsite returns websiteId as expected." );
    is( $args[1], 'post',     "test_createWebsite uses the post request as expected." );
    is( $args[2], '/website', "test_createWebsite uses the /website endpoint as expected." );

    return;
}

sub test_storeWebsiteId : Tests(1) ($self) {
    my @args;
    my $mocks = $self->_get_mocks();
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
            'Cpanel::SafeDir::MK::safemkdir_or_die'            => 1,
            'Cpanel::FileUtils::Write::overwrite'              => 1,
        )
    );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my %website_info = (
        'domain'    => 'rubberduck.tld',
        'company'   => 'The RubberDuck enterprises',
        'title'     => 'Duckpond',
        'firstname' => 'Daffy',
        'lastname'  => 'Duck'
    );
    my $connector = Cpanel::Sitejet::Connector->new();

    ok( lives { $connector->storeWebsiteId( \%website_info, '12345' ) }, "test_storeWebsiteId call works as expected." );

    return;
}

sub test_getWebsiteIdForDomain : Tests(1) ($self) {
    my @args;
    my $mocks = $self->_get_mocks();
    my @mocks = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; } ) );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $connector = Cpanel::Sitejet::Connector->new();

    my $web_Id = $connector->getWebsiteIdForDomain( $mocks->{'domain'} );

    require Cpanel::JSON;
    my $json_content = Cpanel::JSON::Load( $mocks->{'content'} );
    is( $web_Id, $json_content->{'websiteId'}, "test_getWebsiteIdForDomain gets the expected websiteId." );

    return;
}

sub test_getPreviewDataForWebsite : Tests(4) ($self) {
    my @args;
    my $mocks = $self->_get_mocks();
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::request' => sub {
                @args = @_;
                return HTTP::Response->new(200);
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    my $connector = Cpanel::Sitejet::Connector->new();

    my $resp = $connector->getPreviewDataForWebsite( $mocks->{'domain'}, $mocks->{'api_key'} );

    ref_ok( $resp, 'HASH', "test_getPreviewDataForWebsite returns hashref as expected" );
    is( $args[1], 'get',                        "test_getPreviewDataForWebsite uses the get request as expected." );
    is( $args[2], '/website/391160/previewurl', "test_getPreviewDataForWebsite uses the /previewurl endpoint as expected." );
    is( $args[3], $mocks->{'api_key'},          "test_getPreviewDataForWebsite receives the API key as expected." );

    return;
}

sub test_new : Tests(2) ($self) {
    my @mocks = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; }, ) );
    my $ret   = Cpanel::Sitejet::Connector->new();
    isa_ok( $ret, ['Cpanel::Sitejet::Connector'], "test_new  - returns Sitejet Connector object", explain $ret );
    like( $ret->{config_dir}, qr{.cpanel/sitejet}, 'config_dir var initialized' );

    return;
}

sub test_getSSOLinkForWebsite : Tests(6) ($self) {
    my @args;
    my $mocks = $self->_get_mocks();
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my %opts = (
        'domain'     => $mocks->{'domain'},
        'locale'     => 'en',
        'referrer'   => 'something',
        'company_id' => 123
    );

    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::request' => sub {
                @args = @_;
                return HTTP::Response->new(200);
            },
            'Cpanel::Sitejet::Connector::loadApiKey'           => $mocks->{'api_key'},
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );

    my $conn_obj = Cpanel::Sitejet::Connector->new();
    my $resp     = $conn_obj->getSSOLinkForWebsite( \%opts );

    is( $args[1], 'get',                 "test_getSSOLinkForWebsite uses the get request as expected." );
    is( $args[2], '/website/391160/sso', "test_getSSOLinkForWebsite uses the /sso endpoint as expected." );
    is( $args[3], $mocks->{'api_key'},   "test_getSSOLinkForWebsite receives the API key as expected." );
    ref_ok( $args[4], 'HASH', "test_getSSOLinkForWebsite request returns hash ref data as expected." );
    ref_ok( $resp,    'HASH', "test_getSSOLinkForWebsite returns hashref as expected" );

    @mocks = ();
    @mocks = (
        $self->mock_subs(
            'LWP::UserAgent::get' => sub {
                return HTTP::Response->new(404);
            },
            'Cpanel::Sitejet::Connector::loadApiKey' => $mocks->{'api_key'},
            'Cpanel::Exception::create'              => sub {
                return die 'The API call failed with error code';
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );

    $conn_obj = Cpanel::Sitejet::Connector->new();
    like(
        dies { $conn_obj->getSSOLinkForWebsite( \%opts ) },
        qr/The API call failed with error code/,
        "test_getSSOLinkForWebsite dies as expected."
    );

    return;
}

sub test_storeWebsiteTemplateId : Tests(2) ($self) {
    my ( $file_name, $data, $conn_obj );
    my $mocks = $self->_get_mocks();
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
            'Cpanel::Sitejet::Connector::cp_write_json'        => sub {
                ( $conn_obj, $file_name, $data ) = @_;
                return 1;
            },
        )
    );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $connector = Cpanel::Sitejet::Connector->new();

    ok( lives { $connector->storeWebsiteTemplateId( $mocks->{'domain'}, $mocks->{'templateId'} ) }, "test_storeWebsiteTemplateId call works as expected." );

    is( $mocks->{'templateId'}, $data->{'templateId'}, "test_storeWebsiteTemplateId gets the expected templateId." );

    return;
}

sub test_loadApiKey : Tests(2) ($self) {

    my @mocks = (
        $self->mock_subs(
            'Cpanel::Config::LoadCpUserFile::loadcpuserfile' => sub {
                if ( shift eq 'rubberduck' ) {
                    return { SITEJET_API_TOKEN => '7a0596f61f5070543bcb27a8c6d37083' };
                }
                else {
                    return { NOTHING_HERE => '' };
                }
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );

    my $case = 1;
    $Cpanel::user    = 'rubberduck';
    $Cpanel::homedir = "/home/$Cpanel::user";
    my $conn_obj = Cpanel::Sitejet::Connector->new();
    my $token    = $conn_obj->loadApiKey();
    is( $token, '7a0596f61f5070543bcb27a8c6d37083', "test_loadApiKey Valid case$case : $Cpanel::user" );

    $case++;
    $Cpanel::user    = 'daffyduck';
    $Cpanel::homedir = "/home/$Cpanel::user";
    my $conn_obj2 = Cpanel::Sitejet::Connector->new();
    my $mock_file = Test::MockFile->file( "/var/cpanel/users/$Cpanel::user", '' );
    like(
        dies { $conn_obj2->loadApiKey() },
        qr/EntryDoesNotExist/,
        "test_loadApiKey Invalid case$case : $Cpanel::user"
    );

    return;
}

sub test_cp_read_json : Tests(2) ($self) {

    my $user = 'example';
    local $Cpanel::homedir = "/home/$user";
    my $file      = "$Cpanel::homedir/.cpanel/sitejet/mi.json";
    my $data_json = { _content => '{"templateId":"379435","domain":"mi.com","document_root":"/home/example/public_html","company":"dump_mock_json_company"}' };
    my $data_hash = {
        templateId    => 379435,
        domain        => 'mi.com',
        document_root => "$Cpanel::homedir/public_html",
        company       => 'dump_mock_json_company'
    };
    my @mocks     = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; }, ) );
    my $mock_file = Test::MockFile->file( $file, $data_json->{_content} );
    my $conn_obj  = Cpanel::Sitejet::Connector->new();

    my $case   = 1;
    my $result = $conn_obj->cp_read_json($data_json);
    is( $result, $data_hash, "test_cp_read_json Valid case$case : as string" );

    $case++;
    my %result = $conn_obj->cp_read_json($file);
    is( \%result, $data_hash, "test_cp_read_json Valid case$case : as file" );

    return;
}

sub test_cp_get_templates : Tests(2) ($self) {

    my $case  = 0;
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::loadApiKey' => sub { return '7a0596f61f5070543bcb27a8c6d37083'; },
            'Cpanel::Sitejet::Connector::request'    => sub {
                my $templates = [
                    {
                        'name'        => 'Inigo Montoya',
                        'description' => 'You killed my father. Prepare to die.',
                        'previewUrl'  => 'https://www.template-inigomontoya.de.rs',
                        'createdAt'   => '2023-07-13T15:57:38+02:00',
                        'id'          => 379435,
                        'image'       => '/images/1024/6981446/Iningo_Montoya_image.png',
                        'updatedAt'   => '2023-09-12T10:10:18+02:00',
                        'tags'        => [
                            'onepager',
                            'new',
                            'mortuary-services',
                        ],
                    },
                    {
                        'name'        => 'LumeDeAqua',
                        'description' => 'Lumatic Asylum',
                        'previewUrl'  => 'https://www.template-lumedeaqua.de.rs',
                        'createdAt'   => '2023-05-04T09:21:20+02:00',
                        'id'          => 374185,
                        'image'       => '/images/1024/6824140/OG_image_LumeDeAqua.png',
                        'updatedAt'   => '2023-07-27T03:01:16+02:00',
                        'tags'        => [
                            'multipager',
                            'new',
                            'travel',
                        ],
                    },
                    {
                        'name'        => 'PlaceSpace',
                        'description' => 'Move along. Nothing to see here.',
                        'previewUrl'  => 'https://www.template-placespace.de.rs',
                        'createdAt'   => '2023-03-24T17:17:52+01:00',
                        'id'          => 371942,
                        'image'       => '/images/1024/6687157/OG_Image_PlaceSpace.png',
                        'updatedAt'   => '2023-09-25T15:53:19+02:00',
                        'tags'        => [
                            'multipager',
                            'new',
                            'blog',
                            'legal-finance',
                        ],
                    },
                ];
                return $templates;
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    $case++;
    local $Cpanel::homedir = '/home/example';
    my $conn_obj  = Cpanel::Sitejet::Connector->new();
    my $templates = $conn_obj->cp_get_templates();
    is( $#$templates, 2, "test_cp_get_templates Valid case$case : size ok" );

    $case++;
    is( $templates->[0]->{name}, 'Inigo Montoya', "test_cp_get_templates Valid case$case: name=$templates->[0]->{name}" );

    return;
}

sub test_createAccount : Tests(3) ($self) {

    my $case  = 0;
    my @mocks = (
        $self->mock_subs(
            'Cpanel::Config::LoadCpUserFile::loadcpuserfile' => sub {
                my $user = shift;
                if ( $user eq 'rubberduck' ) {
                    return {
                        SITEJET_API_TOKEN => '7a0596f61f5070543bcb27a8c6d37083',
                        UUID              => '15e558ba-08b5-4600-9b53-255dd33ae80e',
                    };
                }
                elsif ( $user eq 'rubberneck' ) {
                    return {
                        UUID => '15e558ba-08b5-4600-9b53-255dd33ae80e',
                    };
                }
                else {
                    return { NOTHING_HERE => '' };
                }
            },
            'Cpanel::Sitejet::Connector::request' => sub {
                return { key => '1edc82ea122482848284c8482e84828f' };
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
        )
    );
    local $Cpanel::homedir = "/home/example";
    my $conn_obj = Cpanel::Sitejet::Connector->new();

    $case++;
    $Cpanel::user = 'inigo';
    my $result = $conn_obj->createAccount();
    is( $result->{key}, '1edc82ea122482848284c8482e84828f', "test_createAccount Valid case$case : $Cpanel::user" );

    $case++;
    $Cpanel::user = 'rubberneck';
    $result       = $conn_obj->createAccount();
    is( $result->{key}, '1edc82ea122482848284c8482e84828f', "test_createAccount Valid case$case : $Cpanel::user" );

    $case++;
    $Cpanel::user = 'rubberduck';
    my $mock_file = Test::MockFile->file( '/var/cpanel/users/rubberduck', '' );
    like(
        dies { $conn_obj->createAccount() },
        qr/InvalidParameter/,
        "test_createAccount Invalid case$case : $Cpanel::user"
    );

    return;
}

sub test_selectTemplateForWebsite : Tests(1) ($self) {

    my @mocks = (
        $self->mock_subs(
            'Cpanel::Sitejet::Connector::getWebsiteIdForDomain'  => sub { return 392386; },
            'Cpanel::Sitejet::Connector::loadApiKey'             => sub { return '452f56ea63b22488920f08de08821965'; },
            'Cpanel::Sitejet::Connector::storeWebsiteTemplateId' => sub { return; },
            'Cpanel::Sitejet::Connector::request'                => sub { return { 'success' => 1 }; },
            'Cpanel::Sitejet::Connector::_check_domain_config'   => sub { return; },
        )
    );

    my $conn_obj = Cpanel::Sitejet::Connector->new();
    my $result   = $conn_obj->selectTemplateForWebsite( 'rubberduck.com', '379435' );
    is( $result->{success}, 1, "test_selectTemplateForWebsite Valid : success" );

    return;
}

sub test_installApiProxy : Tests(3) ($self) {
    my @args;
    my $mocks = $self->_get_mocks();
    my @mocks = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; }, ) );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $connector = Cpanel::Sitejet::Connector->new();

    ok( lives { $connector->installApiProxy( $mocks->{domain}, $mocks->{public_html} ) }, "test_installApiProxy call works as expected." );

    open my $fh, '<', "$mocks->{public_html}/api.php" or die "print unable to open api.php";
    chomp( my @data = <$fh> );
    close $fh;

    my %expected_data = (
        'apiHost'      => "'https://api.sitehub.io'",
        'client_email' => "'rubberduck\@rubberduck.tld'",
    );
    foreach my $content (@data) {
        my ( $key, $value ) = split /=/, $content;
        is( $value, $expected_data{$key}, "test_installApiProxy returns expected data:$value for $key." );
    }

    return;
}

sub test_installFlags : Tests(2) ($self) {
    my ( $bin, @args );
    my $mocks      = $self->_get_mocks();
    my @first_data = ();
    my @mocks      = (
        $self->mock_subs(
            'Cpanel::Tar::load_tarcfg'                  => { 'bin' => '/bin/gtar' },
            'Cpanel::SafeRun::Errors::saferunallerrors' => sub {
                if ( !@first_data ) {
                    @args = @first_data = @_;
                }
                else {
                    @args = @first_data;
                }
                return;
            },
            'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; },
            'File::Path::remove_tree'                          => sub { return; },
        )
    );
    my $mock_file        = Test::MockFile->file( '/var/cpanel/plugins/sitejet/resources/flags.tar.gz', '' );
    my $bundle_mock_file = Test::MockFile->file( "$mocks->{public_html}/._bundles",                    '' );
    my $bundle_mock_dir  = Test::MockFile->new_dir("$mocks->{'public_html'}/bundles");
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $connector     = Cpanel::Sitejet::Connector->new();
    my @expected_args = ( '/bin/gtar', '-C', $mocks->{public_html}, '-v', '-x', '-f', '/var/cpanel/plugins/sitejet/resources/flags.tar.gz' );

    ok( lives { $connector->installFlags( $mocks->{public_html} ) }, "test_installFlags call works as expected." );
    is( \@args, \@expected_args, "test_installFlags returns exact argument list for saferunallerrors" ) or explain @args;

    return;
}

sub test_installLanguages : Tests(12) ($self) {
    my ( $bin, @args );
    my $mocks     = $self->_get_mocks();
    my @mocks     = ( $self->mock_subs( 'Cpanel::Sitejet::Connector::_check_domain_config' => sub { return; }, ) );
    my @lang_data = (
        {
            'lang'            => ['en'],
            'expected_string' => "'en'"
        },
        {
            'lang'            => [ 'en', 'es' ],
            'expected_string' => "'en','es'"
        },
        {
            'lang'            => [ 'ta', 'te' ],
            'expected_string' => "'ta','te'"
        }
    );
    local $Cpanel::user    = $mocks->{'user'};
    local $Cpanel::homedir = $mocks->{'homedir'};
    my $connector = Cpanel::Sitejet::Connector->new();
    my $pre_lang  = q{<script>var a=[};
    my $post_lang = q{];window.location.href='/'+(navigator.languages.find(l=>a.includes((l||'').toLowerCase().substring(0,2)))||a[0]).substring(0,2);</script>};
    foreach my $data_hr (@lang_data) {

        ok( lives { $connector->installLanguages( $mocks->{public_html}, @{ $data_hr->{'lang'} } ) }, "test_installLanguages call works as expected." );

        open my $fh, '<', "$mocks->{public_html}/index.html" or die "print unable to open index.html";
        chomp( my $data = <$fh> );
        if ( $data =~ /^(?<pre_lang>[^']+)(?<lang>[^\];]+)(?<post_lang>.*)/ ) {
            is( $+{pre_lang},  $pre_lang,                     "test_installLanguages writes pre script tag as expected." );
            is( $+{lang},      $data_hr->{'expected_string'}, "test_installLanguages replaces the languages in index.html." );
            is( $+{post_lang}, $post_lang,                    "test_installLanguages writes post script as expected." );
        }
        close $fh;
    }

    return;
}

sub test_rm_old_sitejet_dir : Tests(2) ($self) {

    my $home        = '/home/testoldsjconfig';
    my $sitejet_dir = "$home/sitejet";
    my $extra_file  = "$sitejet_dir/extra_file";

    my %mocks = ();
    $mocks{home}    = Test::MockFile->new_dir($home);
    $mocks{old_dir} = Test::MockFile->new_dir($sitejet_dir);
    $mocks{file}    = Test::MockFile->file( $extra_file, "This is a meaningless file" );

    # Shouldn't remove directory because it's not empty.
    Cpanel::Sitejet::Connector::rm_old_sitejet_dir($home);
    is( -e $sitejet_dir, 1, "test_rm_old_sitejet_dir kept non-empty directory" );

    unlink $extra_file;

    # Unfortunately, rmdir() doesn't work on mocked directories where a file
    # was removed.  Reading the directory shows the file is not there, but
    # Test::MockFile doesn't allow rmdir() to succeed, thinking there's still a
    # file in there.  This ensures the mocked file is actually gone.
    $mocks{file} = undef;

    # Should remove directory because it's now empty.
    Cpanel::Sitejet::Connector::rm_old_sitejet_dir($home);

    is( !-e $sitejet_dir, 1, "test_rm_old_sitejet_dir removed empty directory" );

    return;
}

sub test_is_likely_domain_config : Tests(5) ($self) {

    my $dconfig   = '{"cpanelDomainGUID":"1234","document_root":"/home/testsjdomainconfig/public_html","domain":"test.com","websiteId":"1234"}';
    my $rand_json = '{"hello":"world"}';
    my $home      = '/home/test_sj_dconfig';
    my %mocks     = ();
    $mocks{domain_config}     = Test::MockFile->file( "$home/.cpanel/sitejet/test.com",   $dconfig );
    $mocks{rand_json}         = Test::MockFile->file( "$home/.cpanel/sitejet/some_json",  $rand_json );
    $mocks{not_domain_config} = Test::MockFile->file( "$home/.cpanel/sitejet/not_domain", "Hello world!\n" );
    $mocks{empty_file}        = Test::MockFile->file( "$home/.cpanel/sitejet/empty_file", "" );
    $mocks{dir}               = Test::MockFile->new_dir("$home/.cpanel/sitejet/happy_dir");

    is( Cpanel::Sitejet::Connector::is_likely_domain_config( $mocks{domain_config}->{path},     "test.com" ), 1, "test_is_likely_domain_config correctly identified Sitejet domain configuration file" );
    is( Cpanel::Sitejet::Connector::is_likely_domain_config( $mocks{rand_json}->{path},         "test.com" ), 0, "test_is_likely_domain_config correctly identified non-Sitejet domain configuration file" );
    is( Cpanel::Sitejet::Connector::is_likely_domain_config( $mocks{not_domain_config}->{path}, "test.com" ), 0, "test_is_likely_domain_config correctly identified non-Sitejet domain configuration file" );
    is( Cpanel::Sitejet::Connector::is_likely_domain_config( $mocks{empty_file}->{path},        "test.com" ), 0, "test_is_likely_domain_config correctly identified non-Sitejet domain configuration file" );
    is( Cpanel::Sitejet::Connector::is_likely_domain_config( $mocks{dir}->{path},               "test.com" ), 0, "test_is_likely_domain_config correctly identified directory as not a Sitejet domain configuration file" );

    return;
}

sub test_cp_save_tracking : Tests(2) ($self) {
    my $domain       = 'test.com';
    my $home         = '/home/test_sj_tracking';
    my $config_dir   = "$home/.cpanel/sitejet";
    my $doc_root     = "$home/public_html";
    my $tracking_new = "$config_dir/$domain-files_new";
    local $Cpanel::homedir = $home;

    my @files = sort "$doc_root/index.html", "$doc_root/images/smile.png", "$doc_root/sitemap.xml";
    my $mock_tracking_file = Test::MockFile->file( $tracking_new, '' );

    # The !-e "$home/sitejet" test in Cpanel::Sitejet::Connector::_check_domain_config()
    # will fail without creating the mock directory and then removing it.
    my $mock_old_config = Test::MockFile->dir("$home/sitejet");
    rmdir "$home/sitejet";

    my $connector = Cpanel::Sitejet::Connector->new();
    local %Cpanel::Sitejet::Connector::file_tracking = map { $_ => 1 } @files;
    $connector->cp_save_tracking($domain);

    is( -s $tracking_new, length "@files\n", "test_cp_save_tracking file was updated" );

    open my $FH, "<", $tracking_new or die "Cannot open $tracking_new: $!\n";
    chomp( my @tracking_data = <$FH> );
    close $FH;

    is( \@files, \@tracking_data, "test_cp_save_tracking file contents good" );

    return;
}

sub _get_mocks ($self) {
    my %mocks        = ();
    my @arr          = ();
    my $html_content = qq(<div class="ed-element ed-container banner preset-banner-v3-default");
    $mocks{'user'}            = 'rubberduck';
    $mocks{'domain'}          = 'rubberduck.tld';
    $mocks{'homedir'}         = '/home/rubberduck';
    $mocks{'sitejetdir'}      = "$mocks{'homedir'}/.cpanel/sitejet";
    $mocks{'dir_mock'}        = Test::MockFile->new_dir( $mocks{'sitejetdir'} );
    $mocks{'public_html'}     = "$mocks{'homedir'}/public_html";
    $mocks{'html_mockdir'}    = Test::MockFile->new_dir( $mocks{'public_html'} );
    $mocks{'index_file_mock'} = Test::MockFile->file( "$mocks{'public_html'}/index.html", $html_content );
    $mocks{'content'}         = '{"cpanelDomainGUID":"rubberduck.tld","websiteId":391160,"domain":"rubberduck.tld","templateId":"356033","fullcms":1,"publish_status":1,"language":"en","document_root":"/home/rubberduck/public_html","company":"rubberduck.tld"}';
    $mocks{'file_mock'}       = Test::MockFile->file( "$mocks{sitejetdir}/rubberduck.tld", $mocks{'content'} );
    $mocks{'data'}            = { 'main_domain' => 'rubberduck.tld' };
    $mocks{'api_key'}         = '7a0596f61f5070543bcb27a8c6d37083';
    $mocks{'templateId'}      = 67890;
    my $api_php_tmpl     = '/var/cpanel/plugins/sitejet/resources/api.php.tmpl';
    my $api_php          = $mocks{'public_html'} . "/api.php";
    my $php_tmpl_content = "apiHost='__API_HOST__'\nclient_email='__CLIENT_EMAIL__'";
    $mocks{'mock_php_tmpl'} = Test::MockFile->file( "$api_php_tmpl", $php_tmpl_content );
    $mocks{'mock_api_php'}  = Test::MockFile->file( "$api_php",      '' );
    return \%mocks;
}

1;
