#!/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;

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;

    $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); }

    $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 ensure_recovery_data_protected_item);
    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; }
    sub ensure_recovery_data_protected_item { 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 {}; }
    sub make_server_request { 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 @mock_files = (
    Test::MockFile->file('/usr/local/cpanel/logs/error_log'),
);

subtest 'get_backup_destinations - empty destinations list' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => { Destinations => {} }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 1, 'Metadata result is ok' );
    is( ref $result->{destinations}, 'ARRAY', 'Destinations is an array' );
    is( scalar @{ $result->{destinations} }, 0, 'Destinations list is empty' );
};

subtest 'get_backup_destinations - comet cloud storage' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    'dest-1' => {
                        DestinationType     => 1000,
                        Description         => 'Comet Cloud',
                        StorageLimitEnabled => 1,
                        StorageLimitBytes   => 1099511627776,
                        Statistics          => {
                            ClientProvidedSize => {
                                Size => 107374182400
                            }
                        }
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 1, 'Metadata result is ok' );
    is( scalar @{ $result->{destinations} }, 1, 'One destination returned' );
    is( $result->{destinations}[0]{id}, 'dest-1', 'Destination ID matches' );
    is( $result->{destinations}[0]{storage_type}, 'cloud', 'Storage type is cloud' );
    is( $result->{destinations}[0]{storage_name}, 'Comet Cloud', 'Storage name matches' );
    is( $result->{destinations}[0]{recommended}, 1, 'Cloud storage marked as recommended' );
    is( $result->{destinations}[0]{size_used}, 107374182400, 'Size used matches' );
    is( $result->{destinations}[0]{size_total}, 1099511627776, 'Size total matches' );
};

subtest 'get_backup_destinations - local storage' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    'local-1' => {
                        DestinationType => 1002,
                        Description     => 'Local Backup',
                        LocalcopyPath   => '/var/backups'
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 1, 'Metadata result is ok' );
    is( scalar @{ $result->{destinations} }, 1, 'One destination returned' );
    is( $result->{destinations}[0]{storage_type}, 'local', 'Storage type is local' );
    is( $result->{destinations}[0]{storage_path}, '/var/backups', 'Storage path matches' );
    is( $result->{destinations}[0]{recommended}, 0, 'Local storage not marked as recommended' );
};

subtest 'get_backup_destinations - s3 storage' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    's3-1' => {
                        DestinationType => 4000,
                        Description     => 'AWS S3',
                        S3Server        => 's3.amazonaws.com',
                        S3BucketName    => 'my-backup-bucket'
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 1, 'Metadata result is ok' );
    is( scalar @{ $result->{destinations} }, 1, 'One destination returned' );
    is( $result->{destinations}[0]{storage_type}, 's3', 'Storage type is s3' );
    is( $result->{destinations}[0]{storage_name}, 'AWS S3', 'Storage name matches' );
};

subtest 'get_backup_destinations - multiple destinations' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    'cloud-1' => {
                        DestinationType => 1000,
                        Description     => 'Primary Cloud'
                    },
                    'local-1' => {
                        DestinationType => 1002,
                        Description     => 'Local Backup',
                        LocalcopyPath   => '/backup'
                    },
                    's3-1' => {
                        DestinationType => 4000,
                        Description     => 'S3 Storage',
                        S3Server        => 's3.amazonaws.com',
                        S3BucketName    => 'bucket'
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 1, 'Metadata result is ok' );
    is( scalar @{ $result->{destinations} }, 3, 'Three destinations returned' );
};

subtest 'get_backup_destinations - API call fails' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 500,
            Profile => undef
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( $metadata->{result}, 0, 'Metadata result is not ok' );
    is( ref $result->{destinations}, 'ARRAY', 'Destinations is an array' );
    is( scalar @{ $result->{destinations} }, 0, 'Destinations list is empty' );
};

subtest 'get_backup_destinations - response structure' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    'dest-1' => {
                        DestinationType => 1000,
                        Description     => 'Test Destination'
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    ok( exists $result->{destinations}, 'Response has destinations key' );
    ok( defined $result->{destinations}[0]{id}, 'Destination has id' );
    ok( exists $result->{destinations}[0]{storage_name}, 'Destination has storage_name' );
    ok( exists $result->{destinations}[0]{storage_description}, 'Destination has storage_description' );
    ok( exists $result->{destinations}[0]{storage_type}, 'Destination has storage_type' );
    ok( exists $result->{destinations}[0]{size_used}, 'Destination has size_used' );
    ok( exists $result->{destinations}[0]{size_total}, 'Destination has size_total' );
    ok( exists $result->{destinations}[0]{recommended}, 'Destination has recommended' );
};

subtest 'get_backup_destinations - other storage types' => sub {
    my $mock_api = Test::MockModule->new('Whostmgr::CometBackup::CometBackupAPI');
    $mock_api->redefine( 'make_server_request' => sub {
        return {
            Status  => 200,
            Profile => {
                Destinations => {
                    'ftp-1' => {
                        DestinationType => 5000,
                        Description     => 'FTP Server',
                        FTPServer       => 'ftp.example.com'
                    },
                    'sftp-1' => {
                        DestinationType => 5001,
                        Description     => 'SFTP Server',
                        SFTPServer      => 'sftp.example.com'
                    },
                    'b2-1' => {
                        DestinationType => 5002,
                        Description     => 'Backblaze B2',
                        B2              => { AccountID => '123' }
                    }
                }
            }
        };
    } );

    my $metadata = {};
    my $args     = {};

    my $result = Whostmgr::API::1::CometBackup::get_backup_destinations( $args, $metadata );

    is( scalar @{ $result->{destinations} }, 3, 'Three destinations returned' );
    
    my %types = map { $_->{storage_type} => 1 } @{ $result->{destinations} };
    ok( $types{ftp}, 'FTP storage type recognized' );
    ok( $types{sftp}, 'SFTP storage type recognized' );
    ok( $types{b2}, 'B2 storage type recognized' );
};

done_testing();
