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

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

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

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

use Test::MockModule;
use Test::MockFile;
use Cpanel::JSON;
use File::Temp qw(tempdir tempfile);

# Pre-load stub modules to prevent dependencies from failing
BEGIN {
    $INC{'Cpanel/Plugins/Components/Rules.pm'}             = 1;
    $INC{'Cpanel/Plugins/Components/Rules/Util/NVData.pm'} = 1;
    $INC{'Cpanel/Plugins/Components/Rules/CompanyId.pm'}   = 1;

    # Pre-load Cpanel modules
    $INC{'Cpanel/Server/Type.pm'} = 1;

    package Cpanel::Server::Type;
    sub get_products { return { 'cometbackup' => 1 }; }

    $INC{'Cpanel/PwCache.pm'} = 1;

    package Cpanel::PwCache;
    sub new { return bless {}, shift; }

    $INC{'Cpanel/Config/Users.pm'} = 1;

    package Cpanel::Config::Users;
    sub getcpusers { return qw(user1 user2); }

    # Pre-load CometBackup modules with stubs that can be overridden
    $INC{'Whostmgr/CometBackup/Setup.pm'} = 1;

    package Whostmgr::CometBackup::Setup;
    our @EXPORT = qw(is_comet_agent_installed is_agent_logged_in setup_comet_agent install_comet_agent);
    sub is_comet_agent_installed { return 0; }
    sub is_agent_logged_in       { return 0; }
    sub setup_comet_agent        { return 1; }
    sub install_comet_agent      { return 1; }

    $INC{'Whostmgr/CometBackup/AgentManager.pm'} = 1;

    package Whostmgr::CometBackup::AgentManager;
    our @EXPORT = qw(get_status start);
    sub get_status { return ( 1, 'active' ); }
    sub start      { return ( 1, '' ); }

    $INC{'Whostmgr/CometBackup/CometBackupAPI.pm'} = 1;

    package Whostmgr::CometBackup::CometBackupAPI;
    sub new  { return bless {}, shift; }
    sub call { return {}; }

    $INC{'Whostmgr/CometBackup/Constants.pm'} = 1;

    package Whostmgr::CometBackup::Constants;
    sub get_text_log_file_path { return '/var/log/comet.log'; }

    $INC{'Whostmgr/API/1/Utils.pm'} = 1;

    package Whostmgr::API::1::Utils;
    sub set_metadata_ok    { $_[0]->{result} = 1; }
    sub set_metadata_not_ok { $_[0]->{result} = 0; }
}

use Whostmgr::API::1::CometBackup ();

my $test_dir = tempdir( CLEANUP => 1 );

# Mock the error log to prevent file system access issues
my @mock_files = (
    Test::MockFile->file('/usr/local/cpanel/logs/error_log'),
    Test::MockFile->dir('/nonexistent/path'),
    Test::MockFile->file('/var/cpanel/server_locale'),
);

subtest 'download_restore_job_log - missing JSON parameter' => sub {
    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    ok( !defined $result, 'Result is undef when JSON parameter missing' );
};

subtest 'download_restore_job_log - missing run_uuid' => sub {
    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( {} ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    like( $result->{error}, qr/run_uuid.*required/i, 'Error mentions run_uuid is required' );
};

subtest 'download_restore_job_log - invalid run_uuid format' => sub {
    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => 'not-valid-uuid' } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    like( $result->{error}, qr/run_uuid.*format/i, 'Error mentions run_uuid format' );
};

subtest 'download_restore_job_log - log file not found scenario' => sub {
    my $valid_uuid = '550e8400-e29b-41d4-a716-446655440000';
    my ( $fh, $temp_log_file ) = tempfile( DIR => $test_dir );
    close($fh);
    
    # Create a unique file path that doesn't exist
    my $nonexistent_log = "$test_dir/does_not_exist_$valid_uuid.log";
    
    # Mock the Constants to return our non-existent file path
    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $nonexistent_log; } );
    
    my $metadata   = {};
    my $args       = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok for missing log file' );
};

subtest 'download_restore_job_log - log file is not readable' => sub {
    my $valid_uuid = '550e8400-e29b-41d4-a716-446655440001';
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    close($fh);
    chmod( 0000, $log_file );

    # Mock the Constants to return our temp file
    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    like( $result->{error}, qr/not readable/i, 'Error indicates file not readable' );
    is( $result->{log}, '', 'Log content is empty' );

    # Restore permissions for cleanup
    chmod( 0644, $log_file );
};

subtest 'download_restore_job_log - successful log retrieval' => sub {
    my $valid_uuid  = '550e8400-e29b-41d4-a716-446655440002';
    my $log_content = "Restore job started\nProcessing files\nRestore completed successfully\n";
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    print $fh $log_content;
    close($fh);

    # Mock the Constants to return our temp file
    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, $log_content, 'Log content matches' );
    is( $result->{run_uuid}, $valid_uuid, 'run_uuid is returned' );
    ok( !exists $result->{error}, 'No error in result' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

subtest 'download_restore_job_log - error reading log file with eval exception' => sub {
    my $valid_uuid = '550e8400-e29b-41d4-a716-446655440003';
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    close($fh);

    # Mock the Constants to return our temp file
    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    # Mock Cpanel::LoadFile to throw an exception
    my $loadfile_mock = Test::MockModule->new('Cpanel::LoadFile');
    $loadfile_mock->redefine( 'load', sub { die "File read error"; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    like( $result->{error}, qr/Failed to read/i, 'Error indicates failure to read' );
    is( $result->{log}, '', 'Log content is empty' );
};

subtest 'download_restore_job_log - large log file content' => sub {
    my $valid_uuid  = '550e8400-e29b-41d4-a716-446655440004';
    my $log_content = join( '', map { "Line $_\n" } ( 1 .. 10000 ) );
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    print $fh $log_content;
    close($fh);

    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, $log_content, 'Large log content matches' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

subtest 'download_restore_job_log - empty log file' => sub {
    my $valid_uuid = '550e8400-e29b-41d4-a716-446655440005';
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    close($fh);

    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, '', 'Empty log file returns empty string' );
    is( $result->{run_uuid}, $valid_uuid, 'run_uuid is returned' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

subtest 'download_restore_job_log - various error conditions' => sub {
    # This test verifies that various error conditions are handled properly
    my $valid_uuid = '550e8400-e29b-41d4-a716-446655440010';
    my ( $fh, $temp_log_file ) = tempfile( DIR => $test_dir );
    close($fh);
    
    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $temp_log_file; } );

    my $metadata = {};
    my $args = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    # Verify the function handles calls properly
    is( ref $metadata, 'HASH', 'Metadata is a hash reference' );
    ok( 1, 'Error handling test completed' );
};

subtest 'download_restore_job_log - UUID with different valid formats' => sub {
    # Test various valid UUID formats
    my @valid_uuids = (
        '550e8400-e29b-41d4-a716-446655440006',  # Standard UUID
        '00000000-0000-0000-0000-000000000000',  # All zeros
    );

    for my $uuid (@valid_uuids) {
        my $log_content = "Test log for $uuid\n";
        my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
        print $fh $log_content;
        close($fh);

        my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
        $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

        my $metadata = {};
        my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $uuid } ) };

        my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

        is( $result->{run_uuid}, $uuid, "Valid UUID $uuid accepted" );
    }
};

subtest 'download_restore_job_log - log file with special characters' => sub {
    my $valid_uuid  = '550e8400-e29b-41d4-a716-446655440007';
    my $log_content = "Error: accent marks\nPath: /path/with/slash\nSpecial: !@#\$%^&*()\n";
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    print $fh $log_content;
    close($fh);

    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, $log_content, 'Log content with special characters matches' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

subtest 'download_restore_job_log - symlink to log file' => sub {
    my $valid_uuid  = '550e8400-e29b-41d4-a716-446655440008';
    my $log_content = "Symlinked log content\n";
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    print $fh $log_content;
    close($fh);

    # Create a symlink
    my $symlink = "$test_dir/symlink_log";
    symlink( $log_file, $symlink );

    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $symlink; } );

    my $metadata = {};
    my $args     = { json => Cpanel::JSON::Dump( { run_uuid => $valid_uuid } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, $log_content, 'Symlinked log file content matches' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

subtest 'download_restore_job_log - extra parameters in JSON args are ignored' => sub {
    my $valid_uuid  = '550e8400-e29b-41d4-a716-446655440009';
    my $log_content = "Test log content\n";
    my ( $fh, $log_file ) = tempfile( DIR => $test_dir );
    print $fh $log_content;
    close($fh);

    my $constants_mock = Test::MockModule->new('Whostmgr::CometBackup::Constants');
    $constants_mock->redefine( 'get_text_log_file_path', sub { return $log_file; } );

    my $metadata = {};
    my $args = { json => Cpanel::JSON::Dump( {
        run_uuid     => $valid_uuid,
        extra_param1 => 'value1',
        extra_param2 => 'value2',
    } ) };

    my $result = Whostmgr::API::1::CometBackup::download_restore_job_log( $args, $metadata, {} );

    is( $result->{log}, $log_content, 'Log content retrieved despite extra params' );
    is( $metadata->{result}, 1, 'Metadata result is ok' );
};

done_testing();
