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

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;

# Mock files that might be accessed
my @mock_files = (
    Test::MockFile->file( '/usr/local/cpanel/logs/error_log', '' ),
    Test::MockFile->file( '/var/cpanel/server_locale',        '' ),
    Test::MockFile->dir('/var'),
    Test::MockFile->dir('/var/log'),
    Test::MockFile->file( '/var/log/comet_backup.log', '' ),
    Test::MockFile->dir('/var/cpanel'),
    Test::MockFile->dir('/var/cpanel/comet'),
);

# Mock Logger before loading the module
my $mock_logger = Test::MockModule->new('Whostmgr::CometBackup::Logger');
$mock_logger->redefine(
    'new' => sub {
        return bless { log_level => 'info' }, 'Whostmgr::CometBackup::Logger';
    }
);
$mock_logger->redefine( 'info'                  => sub { } );
$mock_logger->redefine( 'warn'                  => sub { } );
$mock_logger->redefine( 'error'                 => sub { } );
$mock_logger->redefine( 'debug'                 => sub { } );
$mock_logger->redefine( '_ensure_log_directory' => sub { return 1; } );
$mock_logger->redefine( '_rotate_log_if_needed' => sub { return 1; } );
$mock_logger->redefine( '_write_to_log'         => sub { return 1; } );

use Whostmgr::CometBackup::Hooks::AccountsRemove ();

subtest 'describe' => sub {
    my $hooks = Whostmgr::CometBackup::Hooks::AccountsRemove::describe();

    ok ref($hooks) eq 'ARRAY', 'describe returns array ref';
    is scalar(@$hooks), 2, 'Returns two hook descriptors';

    my ( $pre_hook, $post_hook ) = @$hooks;

    # Check pre-hook
    is $pre_hook->{category}, 'Whostmgr',                                                 'Pre-hook category correct';
    is $pre_hook->{event},    'Accounts::Remove',                                         'Pre-hook event correct';
    is $pre_hook->{stage},    'pre',                                                      'Pre-hook stage correct';
    is $pre_hook->{hook},     'Whostmgr::CometBackup::Hooks::AccountsRemove::pre_remove', 'Pre-hook function correct';
    is $pre_hook->{exectype}, 'module',                                                   'Pre-hook exectype correct';

    # Check post-hook
    is $post_hook->{category}, 'Whostmgr',                                                  'Post-hook category correct';
    is $post_hook->{event},    'Accounts::Remove',                                          'Post-hook event correct';
    is $post_hook->{stage},    'post',                                                      'Post-hook stage correct';
    is $post_hook->{hook},     'Whostmgr::CometBackup::Hooks::AccountsRemove::post_remove', 'Post-hook function correct';
    is $post_hook->{exectype}, 'module',                                                    'Post-hook exectype correct';
};

subtest 'pre_remove - success' => sub {
    my $mock_du  = Test::MockModule->new('Whostmgr::CometBackup::DeletedUsers');
    my $mock_map = Test::MockModule->new('Whostmgr::CometBackup::ProtectedItemMap');

    my $recorded_user;
    my $recorded_usage;

    $mock_map->redefine(
        'new' => sub {
            return bless {}, 'Whostmgr::CometBackup::ProtectedItemMap';
        }
    );

    $mock_du->redefine(
        'new' => sub {
            return bless { map => bless {}, 'Whostmgr::CometBackup::ProtectedItemMap' }, 'Whostmgr::CometBackup::DeletedUsers';
        }
    );
    $mock_du->redefine(
        'record_deleted_user' => sub {
            my ( $self, %args ) = @_;
            $recorded_user  = $args{system_user};
            $recorded_usage = $args{estimated_usage_bytes};
            return 1;
        }
    );

    my $context = {};
    my $data    = {
        user   => 'testuser',
        domain => 'example.com',
    };

    my $result = Whostmgr::CometBackup::Hooks::AccountsRemove::pre_remove( $context, $data );

    is $result,         1,          'pre_remove returns success';
    is $recorded_user,  'testuser', 'User was recorded';
    is $recorded_usage, undef,      'Usage was undef (will be updated later)';
};

subtest 'pre_remove - no username' => sub {
    my $context = {};
    my $data    = {
        domain => 'example.com',
    };

    my $result = Whostmgr::CometBackup::Hooks::AccountsRemove::pre_remove( $context, $data );

    is $result, 1, 'pre_remove returns success even without username';
};

subtest 'pre_remove - exception handling' => sub {
    my $mock_du  = Test::MockModule->new('Whostmgr::CometBackup::DeletedUsers');
    my $mock_map = Test::MockModule->new('Whostmgr::CometBackup::ProtectedItemMap');

    $mock_map->redefine(
        'new' => sub {
            return bless {}, 'Whostmgr::CometBackup::ProtectedItemMap';
        }
    );

    $mock_du->redefine(
        'new' => sub {
            die "Database error\n";
        }
    );

    my $context = {};
    my $data    = {
        user   => 'testuser',
        domain => 'example.com',
    };

    # Should not die even if DeletedUsers->new fails
    my $result = lives {
        Whostmgr::CometBackup::Hooks::AccountsRemove::pre_remove( $context, $data );
    };

    ok defined($result), 'pre_remove does not die on exception';
    is $result, 1, 'pre_remove returns success even on error';
};

subtest 'post_remove - success' => sub {
    my $mock_du  = Test::MockModule->new('Whostmgr::CometBackup::DeletedUsers');
    my $mock_map = Test::MockModule->new('Whostmgr::CometBackup::ProtectedItemMap');

    my $recorded_user;
    my $recorded_usage;

    $mock_map->redefine(
        'new' => sub {
            return bless {}, 'Whostmgr::CometBackup::ProtectedItemMap';
        }
    );

    $mock_du->redefine(
        'new' => sub {
            return bless { map => bless {}, 'Whostmgr::CometBackup::ProtectedItemMap' }, 'Whostmgr::CometBackup::DeletedUsers';
        }
    );
    $mock_du->redefine(
        'record_deleted_user' => sub {
            my ( $self, %args ) = @_;
            $recorded_user  = $args{system_user};
            $recorded_usage = $args{estimated_usage_bytes};
            return 1;
        }
    );

    my $context = {};
    my $data    = {
        user        => 'testuser',
        uid         => 1001,
        homedir     => '/home/testuser',
        skipacctbak => 0,
    };

    my $result = Whostmgr::CometBackup::Hooks::AccountsRemove::post_remove( $context, $data );

    is $result,         1,          'post_remove returns success';
    is $recorded_user,  'testuser', 'User was recorded';
    is $recorded_usage, undef,      'Usage was undef';
};

subtest 'post_remove - no username' => sub {
    my $context = {};
    my $data    = {
        uid     => 1001,
        homedir => '/home/testuser',
    };

    my $result = Whostmgr::CometBackup::Hooks::AccountsRemove::post_remove( $context, $data );

    is $result, 1, 'post_remove returns success even without username';
};

subtest 'post_remove - exception handling' => sub {
    my $mock_du  = Test::MockModule->new('Whostmgr::CometBackup::DeletedUsers');
    my $mock_map = Test::MockModule->new('Whostmgr::CometBackup::ProtectedItemMap');

    $mock_map->redefine(
        'new' => sub {
            return bless {}, 'Whostmgr::CometBackup::ProtectedItemMap';
        }
    );

    $mock_du->redefine(
        'new' => sub {
            die "Database error\n";
        }
    );

    my $context = {};
    my $data    = {
        user    => 'testuser',
        uid     => 1001,
        homedir => '/home/testuser',
    };

    # Should not die even if DeletedUsers->new fails
    my $result = lives {
        Whostmgr::CometBackup::Hooks::AccountsRemove::post_remove( $context, $data );
    };

    ok defined($result), 'post_remove does not die on exception';
    is $result, 1, 'post_remove returns success even on error';
};

done_testing();
