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

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

use cPstrict;

use Test2::V0;
use Test2::Tools::Compare;
use Test2::Tools::Explain;
use Test2::Tools::Subtest;
use Test2::Plugin::NoWarnings;

use Test::MockObject;
use Test::Cpanel::Policy;
use Cpanel::Result ();
use Cpanel::Args   ();

use parent qw(
  Cpanel::TestObj
);

use Cpanel::API::Sitejet       ();
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 ) {
    return $self->SUPER::runtests(@args);
}

sub test_create_account : Tests(5) ($self) {
    my ( $namespace, $module, $action, $api_key );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::createAccount' => sub {
            my $ret = {
                'key' => 'api_key',
            };
            return $ret;
        },
        'Cpanel::AdminBin::Call::call' => sub {
            ( $namespace, $module, $action, $api_key ) = @_;
            return;
        },
    );

    Cpanel::API::Sitejet::create_account( $args, $result );

    is( $namespace,      'Cpanel',                                    "AdminBin namespace is Cpanel" )       or diag explain $namespace;
    is( $module,         'sitejet',                                   "AdminBin module is sitejet" )         or diag explain $module;
    is( $action,         'ADD_API_TOKEN',                             "AdminBin action is ADD_API_TOKEN" )   or diag explain $action;
    is( $api_key,        'api_key',                                   "AdminBin data is the api key" )       or diag explain $api_key;
    is( $result->{data}, Cpanel::Sitejet::Connector::createAccount(), "UAPI call returns sitejet response" ) or diag explain $result;
}

sub test_get_templates : Tests(1) ($self) {
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_get_templates' => sub {
            my $ret = [
                {
                    "createdAt"   => "2023-03-18T10:01:02+01:00",
                    "description" => "",
                    "id"          => 371507,
                    "image"       => "/images/1024/6687284/OG_Image_Drive.png",
                    "name"        => "Drive",
                    "previewUrl"  => "https://www.template-drive.de.rs",
                    "tags"        => [
                        "onepager",
                        "new",
                        "services"
                    ],
                    "updatedAt" => "2023-07-03T16:22:12+02:00"
                },
                {
                    "createdAt"   => "2018-11-08T19:16:19+01:00",
                    "description" => '',
                    "id"          => 145599,
                    "image"       => "/images/1024/2958576/wireframe.jpg",
                    "name"        => "Wireframe",
                    "previewUrl"  => "https://www.template-wireframe.de.rs",
                    "tags"        => [
                        "multipager",
                        "trending",
                        "wireframe"
                    ],
                    "updatedAt" => "2022-12-09T18:18:00+01:00"
                },
            ];
            return $ret;
        },
    );

    Cpanel::API::Sitejet::get_templates( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::cp_get_templates, "UAPI call returns sitejet response" ) or diag explain $result->{data};
}

sub test_set_template : Tests(3) ($self) {
    my ( $connector, $domain, $templateID );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => "example.com", 'templateId' => "12345" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::selectTemplateForWebsite' => sub {
            ( $connector, $domain, $templateID ) = @_;
            return { "success" => "true" };
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );

    Cpanel::API::Sitejet::set_template( $args, $result );
    is( $domain,         $args->{_args}{'domain'},     "domain is passed in correctly" )             or diag explain $domain;
    is( $templateID,     $args->{_args}{'templateId'}, "templateId is passed in correctly" )         or diag explain $templateID;
    is( $result->{data}, { "success" => "true" },      "data field contains success key and value" ) or diag explain $result;
}

sub test_get_sso_link : Tests(3) ($self) {
    my ( $connector, $domain, $referrer );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => "example.com", 'referrer' => "cpanel" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::getSSOLinkForWebsite' => sub {
            ( $connector, $domain, $referrer ) = @_;
            my $ret = 'example.com/SSO_link';
            return $ret;
        },
        'Cpanel::API::Sitejet::_validate_user_domain'  => 1,
        'Cpanel::Locale::Utils::User::get_user_locale' => 'en'
    );

    Cpanel::API::Sitejet::get_sso_link( $args, $result );
    is( $domain,         $args->{_args}{'domain'},                           "domain is passed in correctly" )   or diag explain $domain;
    is( $referrer,       $args->{_args}{'referrer'},                         "referrer is passed in correctly" ) or diag explain $referrer;
    is( $result->{data}, Cpanel::Sitejet::Connector::getSSOLinkForWebsite(), "data field contains SSO link" )    or diag explain $result;
}

sub test_get_preview_url : Tests(1) ($self) {
    my ( $connector, $websiteId );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'websiteId' => "12345" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_getPreviewUrl' => sub {
            ( $connector, $websiteId ) = @_;
            my $ret = 'example.com/website/12345/previewurl';
            return $ret;
        },
    );

    Cpanel::API::Sitejet::get_preview_url( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::cp_getPreviewUrl(), "data field contains preview url" ) or diag explain $result;
}

sub test_get_api_token : Tests(1) ($self) {
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::loadApiKey' => sub {
            my $ret = 'api_key ';
            return $ret;
        },
    );

    Cpanel::API::Sitejet::get_api_token( $args, $result );
    is( $result->{data}, Cpanel::Sitejet::Connector::loadApiKey(), "data field contains api token" ) or diag explain $result;
}

sub test_add_api_token : Tests(4) ($self) {
    my ( $namespace, $module, $action, $api_key );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "api_token" => "api_key" } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::loadApiKey' => sub {
            my $ret = 'api_key ';
            return $ret;
        },
        'Cpanel::AdminBin::Call::call' => sub {
            ( $namespace, $module, $action, $api_key ) = @_;
            return;
        },
    );

    Cpanel::API::Sitejet::add_api_token( $args, $result );
    is( $namespace, 'Cpanel',                    "AdminBin namespace is Cpanel" )     or diag explain $namespace;
    is( $module,    'sitejet',                   "AdminBin module is sitejet" )       or diag explain $module;
    is( $action,    'ADD_API_TOKEN',             "AdminBin action is ADD_API_TOKEN" ) or diag explain $action;
    is( $api_key,   $args->{_args}{"api_token"}, "AdminBin data is the api key" )     or diag explain $api_key;
}

sub test_create_website : Tests(2) ($self) {
    my ( $connector, $website_info_hr );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new(
        {
            "domain"  => "example.com",
            "company" => "WebPros",
        }
    );    # Testing with minimum params first
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::createWebsite' => sub {
            ( $connector, $website_info_hr ) = @_;
            $website_info_hr->{website_id} = "12345";
            return $website_info_hr->{website_id};
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );

    Cpanel::API::Sitejet::create_website( $args, $result );

    is( $result->{data}, $website_info_hr->{website_id}, "create_website returns website id (min params)" ) or diag explain $result;

    $args->{_args}{'Title'}     = 'myWebsite';
    $args->{_args}{'firstname'} = 'example';
    $args->{_args}{'lastname'}  = 'user';
    $args->{_args}{'street'}    = 'main st';
    $args->{_args}{'zip'}       = '00000';
    $args->{_args}{'city'}      = 'city';
    $args->{_args}{'country'}   = 'country';
    $args->{_args}{'email'}     = 'example.user@email.com';
    $args->{_args}{'phone'}     = '999-999-9999';
    $args->{_args}{'note'}      = 'example user';
    $args->{_args}{'metadata'}  = { 'website_id' => "12345", 'template_id' => "54321" };
    $args->{_args}{'assignTo'}  = 'example user';

    Cpanel::API::Sitejet::create_website( $args, $result );

    is( $result->{data}, $website_info_hr->{website_id}, "create_website returns website id (all params)" ) or diag explain $result;
}

sub test_get_user_site_metadata : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "domain" => "example.com" } );
    my $metadata;
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
            ( $connector, $domain ) = @_;
            $metadata = {
                "company"         => "example_company",
                "domain"          => "example.com",
                "fullcms"         => 1,
                "language"        => "en",
                "pleskDomainGUID" => "example.com",
                "publish_status"  => 1,
                "templateId"      => "333333",
                "websiteId"       => "999999",
            };
            return $metadata;
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );

    Cpanel::API::Sitejet::get_user_site_metadata( $args, $result );

    is( $result->{data}, $metadata, "get_user_site_metadata returns metadata" ) or diag explain $result;
}

sub test_get_all_sites_metadata : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( {} );
    my $metadata;
    my @mocks = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_load_all_sitejet_domains_metadata' => sub {
            ( $connector, $domain ) = @_;
            $metadata = [
                {
                    "company"         => "example_company",
                    "domain"          => "example.com",
                    "fullcms"         => 1,
                    "language"        => "en",
                    "pleskDomainGUID" => "example.com",
                    "publish_status"  => 1,
                    "templateId"      => "333333",
                    "websiteId"       => "999999",
                }
            ];
            return $metadata;
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );

    Cpanel::API::Sitejet::get_all_sites_metadata( $args, $result );

    is( $result->{data}, $metadata, "get_all_sites_metadata returns metadata" ) or diag explain $result;
}

sub test_publish : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { "domain" => "example.com" } );
    $Cpanel::homedir = "home";
    $Cpanel::user    = "test";
    my $mock_autodie = Test::MockModule->new('Cpanel::Autodie');
    $mock_autodie->define(
        'symlink' => 1,
    );
    my @mocks = $self->mock_subs(
        'Cpanel::Daemonizer::Tiny::run_as_daemon' => sub {
            return "999";
        },
        'Cpanel::API::Sitejet::_create_logging_stream_dir' => sub {
            return ( "path/to/log/txt", "LOG_ENTRY" );
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );
    Cpanel::API::Sitejet::publish( $args, $result );

    is( $result->{data}, { "pid" => "999", "log_entry" => "LOG_ENTRY", "user" => $Cpanel::user }, "publish returns success" ) or diag explain $result;
}

sub _validate_user_domain : Tests(1) ($self) {
    my @mocks = $self->mock_subs(
        'Cpanel::DomainLookup::DocRoot::getdocroots' => {
            'foo.bar.tld'  => '/some/where',
            'same.bar.tld' => '/some/where/else',
            'main.tld'     => '/my/docroot',
            'parked.tld'   => '/my/docroot',
            '*.real.tld'   => '/wildcard/docroot',
            ( map { ( "$_.parked.tld" => "/my/$_" ) } qw( cpanel mail www ) ),
        },
    );
    my $ret = Cpanel::API::Sitejet::_validate_user_domain('main.tld');

    is( $ret, 1, "_validate_user_domain happy path returns success" );
}

sub test_get_sitebuilder_domain_statuses : Tests(1) ($self) {
    my ( $connector, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => 'example.com' } );
    my @mocks  = $self->mock_subs(
        'Cpanel::Sitejet::Connector::cp_list_all_domain_sitebuilders' => sub {
            ( $connector, $domain ) = @_;
            return $domain;
        },
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
    );

    Cpanel::API::Sitejet::get_sitebuilder_domain_statuses( $args, $result );
    is( $domain, 'example.com', "connector module receives the domain" ) or diag explain $domain;
}

sub test_disk_quota_check : Tests(4) ($self) {
    my ( $namespace, $module, $action, $domain );
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => 'example.com' } );
    my @mocks  = $self->mock_subs(
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
        'Cpanel::Sitejet::Publish::get_document_root' => '/home/user/public_html',
        'Cpanel::AdminBin::Call::call'                => sub {
            ( $namespace, $module, $action, $domain ) = @_;
            return;
        },
    );

    Cpanel::API::Sitejet::disk_quota_check( $args, $result );

    is( $namespace, 'Cpanel',           "AdminBin namespace is Cpanel" )        or diag explain $namespace;
    is( $module,    'sitejet',          "AdminBin module is sitejet" )          or diag explain $module;
    is( $action,    'DISK_QUOTA_CHECK', "AdminBin action is DISK_QUOTA_CHECK" ) or diag explain $action;
    is( $domain,    'example.com',      "AdminBin data is the domain" )         or diag explain $domain;

    return;
}

sub test_get_all_user_sitejet_info : Tests(8) ($self) {
    my ( $namespace, $module, $action, $domain_adminbin );
    my $connector;
    my $domain_metadata;
    my $domain_statuses;
    my $metadata;
    my $statuses;
    my $quota;
    my $result = Cpanel::Result->new();
    my $args   = Cpanel::Args->new( { 'domain' => 'example.com' } );
    $Cpanel::homedir = "home";
    $Cpanel::user    = "testuser";
    my @mocks = $self->mock_subs(
        'Cpanel::API::Sitejet::_validate_user_domain' => 1,
        'Cpanel::Sitejet::Publish::get_document_root' => '/home/testuser/public_html',
        'Cpanel::AdminBin::Call::call'                => sub {
            ( $namespace, $module, $action, $domain_adminbin ) = @_;
            $quota = {
                'example.com' => {
                    'required_space'   => 22,
                    'can_backup'       => 1,
                    'available_space'  => 281,
                    'is_docroot_empty' => 0
                }
            };
            return $quota;
        },
        'Cpanel::Sitejet::Connector::cp_load_sitejet_metadata' => sub {
            ( $connector, $domain_metadata ) = @_;
            $metadata = {
                "company"         => "example_company",
                "domain"          => "example.com",
                "fullcms"         => 1,
                "language"        => "en",
                "pleskDomainGUID" => "example.com",
                "publish_status"  => 1,
                "templateId"      => "333333",
                "websiteId"       => "999999",
                'zz_light_bg'     => "",
                'zz_dark_bg'      => "",
            };
            return $metadata;
        },
        'Cpanel::Sitejet::Connector::cp_load_all_sitejet_domains_metadata' => sub {
            ($connector) = @_;
            $metadata = {
                "example.com" => {
                    "company"         => "example_company",
                    "domain"          => "example.com",
                    "fullcms"         => 1,
                    "language"        => "en",
                    "pleskDomainGUID" => "example.com",
                    "publish_status"  => 1,
                    "templateId"      => "333333",
                    "websiteId"       => "999999",
                    'zz_light_bg'     => "",
                    'zz_dark_bg'      => "",
                }
            };
            return $metadata;
        },
        'Cpanel::Sitejet::Connector::cp_list_all_domain_sitebuilders' => sub {
            ( $connector, $domain_statuses ) = @_;
            $statuses = [
                {
                    'info' => {
                        'has_sitejet_published'  => 1,
                        'is_sitejet'             => 1,
                        'has_sitejet_templateid' => 1,
                        'has_sitejet_website'    => 1
                    },
                    'domain' => 'example.com'
                }
            ];
            return $statuses;
        }
    );

    Cpanel::API::Sitejet::get_all_user_sitejet_info( $args, $result );

    my $final_data = [
        {
            'metadata' => $metadata,
            'status'   => $statuses->[0]->{info},
            'quota'    => $quota->{$domain_adminbin},
            'domain'   => $statuses->[0]->{domain},
        }
    ];

    is( $namespace,       'Cpanel',           "AdminBin namespace is Cpanel" )        or diag explain $namespace;
    is( $module,          'sitejet',          "AdminBin module is sitejet" )          or diag explain $module;
    is( $action,          'DISK_QUOTA_CHECK', "AdminBin action is DISK_QUOTA_CHECK" ) or diag explain $action;
    is( $domain_adminbin, 'example.com',      "AdminBin data is the domain" )         or diag explain $domain_adminbin;

    is( $domain_metadata, 'example.com', "domain sent to cp_load_all_sitejet_domains_metadata" ) or diag explain $domain_adminbin;
    is( $domain_statuses, 'example.com', "domain sent to cp_list_all_domain_sitebuilders" )      or diag explain $domain_statuses;

    is( $result->{data}, $final_data, "returned data is correct in format and content" ) or diag explain $result;

    $result = Cpanel::Result->new();
    $args   = Cpanel::Args->new( {} );

    Cpanel::API::Sitejet::get_all_user_sitejet_info( $args, $result );

    $final_data = [
        {
            'metadata' => $metadata->{'example.com'},
            'status'   => $statuses->[0]->{info},
            'quota'    => $quota->{'example.com'},
            'domain'   => $statuses->[0]->{domain},
        }
    ];

    is( $result->{data}, $final_data, "returned data is correct in format and content" ) or diag explain $result;
}
