#!/usr/local/cpanel/3rdparty/bin/perl -w
#                                      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

# BEGIN Augment generated code block

use cPstrict;

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

use Test::MockModule qw/strict/;

use Test::Cpanel::Policy testing => 'Cpanel::Plugins::Components::Rules::Random';

use Cpanel::Plugins::Components::Rules::Random ();

# Mock Cpanel::Logger to prevent log file access during tests
my $mock_logger = Test::MockModule->new('Cpanel::Logger');
$mock_logger->redefine(
    'logger' => sub {
        return bless {}, 'MockLogger';
    }
);

# Mock logger methods to be no-ops
{

    package MockLogger;
    sub info  { return; }
    sub warn  { return; }
    sub error { return; }
    sub debug { return; }
}

subtest 'Random configuration validation' => sub {

    subtest 'missing sample_size fails' => sub {
        my $config = { rule => { true => 1 } };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/Random requires 'sample_size' configuration/,
          'Dies when sample_size is missing';
    };

    subtest 'invalid sample_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 'invalid'
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/sample_size must be a positive integer/,
          'Dies with invalid sample_size';
    };

    subtest 'zero sample_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 0
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/sample_size must be a positive integer/,
          'Dies with zero sample_size';
    };

    subtest 'negative sample_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => -1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/sample_size must be a positive integer/,
          'Dies with negative sample_size';
    };
};

subtest 'Fleet size configuration validation' => sub {

    subtest 'valid fleet_size works' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            fleet_size  => 50000
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();
        ok( $result == 0 || $result == 1, 'Valid fleet_size produces boolean result' );
    };

    subtest 'invalid fleet_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            fleet_size  => 'invalid'
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/fleet_size must be a positive integer/,
          'Dies with invalid fleet_size';
    };

    subtest 'zero fleet_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            fleet_size  => 0
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/fleet_size must be a positive integer/,
          'Dies with zero fleet_size';
    };

    subtest 'fleet_size smaller than sample_size fails' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            fleet_size  => 500
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        like dies { $filter->is_allowed() },
          qr/fleet_size must be greater than or equal to sample_size/,
          'Dies when fleet_size < sample_size';
    };

    subtest 'fleet_size equal to sample_size works' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            fleet_size  => 1000
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();
        ok( $result == 0 || $result == 1, 'fleet_size equal to sample_size produces boolean result' );
    };

    subtest 'default fleet_size when not specified' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();
        ok( $result == 0 || $result == 1, 'Default fleet_size (100000) works when not specified' );
    };
};

subtest 'Random decision generation' => sub {

    subtest 'generates boolean results' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);

        # Test multiple times to ensure we get boolean results
        for my $i ( 1 .. 10 ) {
            my $result = $filter->is_allowed();
            ok( $result == 0 || $result == 1, "Random decision $i is boolean" );
        }
    };

    subtest 'distribution test with high probablity sample: 1/2 of population' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 50000            # High probability
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);

        my $true_count  = 0;
        my $total_tests = 100;

        for my $i ( 1 .. $total_tests ) {
            $true_count++ if $filter->is_allowed();
        }

        # With high sample_size, we should get mostly true results
        # Allow some variance due to randomness
        ok(
            $true_count > $total_tests * 0.3,
            "High sample_size produces reasonable number of true results: $true_count/$total_tests"
        );
    };

    subtest 'fleet_size affects probability' => sub {

        # Test with small fleet size (high probability)
        my $config_small_fleet = {
            rule        => { true => 1 },
            sample_size => 500,
            fleet_size  => 1000             # 50% probability
        };

        my $filter_small = Cpanel::Plugins::Components::Rules::Random->new($config_small_fleet);

        my $true_count_small = 0;
        my $total_tests      = 100;

        for my $i ( 1 .. $total_tests ) {
            $true_count_small++ if $filter_small->is_allowed();
        }

        # Test with large fleet size (low probability)
        my $config_large_fleet = {
            rule        => { true => 1 },
            sample_size => 500,
            fleet_size  => 100000           # 0.5% probability
        };

        my $filter_large = Cpanel::Plugins::Components::Rules::Random->new($config_large_fleet);

        my $true_count_large = 0;

        for my $i ( 1 .. $total_tests ) {
            $true_count_large++ if $filter_large->is_allowed();
        }

        # Small fleet should have higher selection rate than large fleet
        # Allow for randomness variance, but expect clear difference
        note("Small fleet (50% prob): $true_count_small/$total_tests selected");
        note("Large fleet (0.5% prob): $true_count_large/$total_tests selected");

        # This is probabilistic, so we can't guarantee exact results,
        # but we can verify both produce valid boolean results
        ok(
            $true_count_small >= 0 && $true_count_small <= $total_tests,
            'Small fleet produces valid selection count'
        );
        ok(
            $true_count_large >= 0 && $true_count_large <= $total_tests,
            'Large fleet produces valid selection count'
        );
    };

    subtest 'production data size: fleet_size 29500, sample_size 10000' => sub {

        # Test with your specific production parameters
        my $config = {
            rule        => { true => 1 },
            sample_size => 10000,           # Target selection size
            fleet_size  => 29500            # Total fleet size
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);

        my $true_count  = 0;
        my $total_tests = 100;

        for my $i ( 1 .. $total_tests ) {
            $true_count++ if $filter->is_allowed();
        }

        # Calculate expected probability: 10000/29500 = ~33.90%
        # For 100 tests, we expect around 34 selections with some variance
        my $expected_percentage = ( 10000 / 29500 ) * 100;

        note("Production data size test: fleet_size=29500, sample_size=10000");
        note( "Expected selection probability: " . sprintf( "%.2f%%", $expected_percentage ) );
        note( "Actual selections: $true_count/$total_tests (" . sprintf( "%.1f%%", ( $true_count / $total_tests ) * 100 ) . ")" );

        # Verify results are boolean and within reasonable range
        ok(
            $true_count >= 0 && $true_count <= $total_tests,
            'Production data size produces valid selection count'
        );

        # With 34% probability, expect results roughly in range of 20-50% allowing for randomness
        ok(
            $true_count >= 20 && $true_count <= 60,
            "Selection count ($true_count) is within expected range for 34% probability"
        );
    };
};

subtest 'Cache functionality' => sub {

    # Mock file operations to avoid real file system access
    my %mock_files;
    my $mock_slurper = Test::MockModule->new('Cpanel::Slurper');
    my $mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

    $mock_slurper->redefine(
        'read' => sub {
            my ($file) = @_;
            return $mock_files{$file} if exists $mock_files{$file};
            die "No such file or directory: $file";
        }
    );

    $mock_writer->redefine(
        'overwrite' => sub {
            my ( $file, $content, $perms ) = @_;
            $mock_files{$file} = $content;
            return 1;
        }
    );

    subtest 'cache file creation and reading' => sub {
        my $cache_file = '/tmp/test_cache.dat';

        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);

        # First call should create cache
        my $first_result = $filter->is_allowed();
        ok( $first_result == !!0 || $first_result == !!1, 'First call produces boolean result' );

        # Verify cache file was created with correct content
        my $cached_content = $mock_files{$cache_file};
        chomp $cached_content;
        is( ( $cached_content ? !!1 : !!0 ), $first_result, 'Cache file contains correct decision' );

        # Second call should return same result from cache
        my $second_result = $filter->is_allowed();
        is( $second_result, $first_result, 'Second call returns cached result' );
    };

    subtest 'cache persistence across filter instances' => sub {
        my $cache_file = '/tmp/persistence_cache.dat';
        $mock_files{$cache_file} = "1\n";

        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file
        };

        # First filter instance
        my $filter1 = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result1 = $filter1->is_allowed();
        is( $result1, !!1, 'First instance reads cached value correctly' );

        # Second filter instance with same config
        my $filter2 = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result2 = $filter2->is_allowed();
        is( $result2, !!1, 'Second instance reads same cached value' );

        is( $result1, $result2, 'Both instances return same cached result' );
    };

    subtest 'invalid cache content handling' => sub {
        my $cache_file = '/tmp/invalid_cache.dat';

        # Test with invalid content
        $mock_files{$cache_file} = "invalid\n";

        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should generate new decision and overwrite invalid cache
        ok( $result == !!0 || $result == !!1, 'Invalid cache content triggers new decision' );

        # Verify cache was overwritten with valid content
        my $new_content = $mock_files{$cache_file};
        chomp $new_content;
        is( ( $new_content ? !!1 : !!0 ), $result, 'Invalid cache was overwritten with valid decision' );
    };

    subtest 'cache with different decisions' => sub {

        # Test cache with decision 0
        my $cache_file_0 = '/tmp/cache_0.dat';
        $mock_files{$cache_file_0} = "0\n";

        my $config_0 = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file_0
        };

        my $filter_0 = Cpanel::Plugins::Components::Rules::Random->new($config_0);
        my $result_0 = $filter_0->is_allowed();
        is( $result_0, !!0, 'Cache with decision 0 returns 0' );

        # Test cache with decision 1
        my $cache_file_1 = '/tmp/cache_1.dat';
        $mock_files{$cache_file_1} = "1\n";

        my $config_1 = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file_1
        };

        my $filter_1 = Cpanel::Plugins::Components::Rules::Random->new($config_1);
        my $result_1 = $filter_1->is_allowed();
        is( $result_1, !!1, 'Cache with decision 1 returns 1' );
    };

    subtest 'no cache file specified' => sub {
        my $config = {
            rule        => { true => 1 },
            sample_size => 1000

              # No cache_file specified
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);

        # Multiple calls should potentially return different results
        # since no caching is happening
        for my $i ( 1 .. 10 ) {
            my $result = $filter->is_allowed();
            ok( $result == !!0 || $result == !!1, "Result $i is boolean without cache" );
        }
    };

    subtest 'cache file permissions' => sub {
        my $cache_file = '/tmp/permissions_cache.dat';

        my $config = {
            rule        => { true => 1 },
            sample_size => 1000,
            cache_file  => $cache_file
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Verify file was created and has content
        ok( exists $mock_files{$cache_file}, 'Cache file was created' );

        my $content = $mock_files{$cache_file};
        chomp $content;
        ok( $content =~ /^[01]$/, 'Cache file contains valid boolean content' );
    };
};

subtest 'Cache method unit tests' => sub {

    # Mock file operations for direct method testing
    my %method_mock_files;
    my $method_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
    my $method_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

    $method_mock_slurper->redefine(
        'read' => sub {
            my ($file) = @_;
            return $method_mock_files{$file} if exists $method_mock_files{$file};
            die "No such file or directory: $file";
        }
    );

    $method_mock_writer->redefine(
        'overwrite' => sub {
            my ( $file, $content, $perms ) = @_;
            $method_mock_files{$file} = $content;
            return 1;
        }
    );

    subtest 'read_cache method' => sub {
        my $filter = Cpanel::Plugins::Components::Rules::Random->new(
            {
                rule        => { true => 1 },
                sample_size => 1000
            }
        );

        subtest 'read valid cache content' => sub {
            my $cache_file = '/tmp/read_test_0.dat';
            $method_mock_files{$cache_file} = "0\n";

            my $result = $filter->read_cache($cache_file);
            is( $result, 0, 'read_cache returns 0 for valid cache with 0' );
        };

        subtest 'read valid cache content with 1' => sub {
            my $cache_file = '/tmp/read_test_1.dat';
            $method_mock_files{$cache_file} = "1\n";

            my $result = $filter->read_cache($cache_file);
            is( $result, 1, 'read_cache returns 1 for valid cache with 1' );
        };

        subtest 'read invalid cache content' => sub {
            my $cache_file = '/tmp/read_test_invalid.dat';
            $method_mock_files{$cache_file} = "invalid\n";

            my $result = $filter->read_cache($cache_file);
            is( $result, undef, 'read_cache returns undef for invalid content' );
        };

        subtest 'read non-existent cache file' => sub {
            my $cache_file = '/tmp/non_existent.dat';

            # Don't add to mock files

            my $result = $filter->read_cache($cache_file);
            is( $result, undef, 'read_cache returns undef for non-existent file' );
        };

        subtest 'read empty cache file' => sub {
            my $cache_file = '/tmp/read_test_empty.dat';
            $method_mock_files{$cache_file} = "";

            my $result = $filter->read_cache($cache_file);
            is( $result, undef, 'read_cache returns undef for empty file' );
        };

        subtest 'read cache with extra whitespace' => sub {
            my $cache_file = '/tmp/read_test_whitespace.dat';
            $method_mock_files{$cache_file} = "  1  \n";

            my $result = $filter->read_cache($cache_file);
            is( $result, undef, 'read_cache returns undef for content with extra whitespace' );
        };
    };

    subtest 'write_cache method' => sub {
        my $filter = Cpanel::Plugins::Components::Rules::Random->new(
            {
                rule        => { true => 1 },
                sample_size => 1000
            }
        );

        subtest 'write decision 0' => sub {
            my $cache_file = '/tmp/write_test_0.dat';

            my $result = $filter->write_cache( $cache_file, 0 );
            is( $result, 1, 'write_cache returns 1 on success' );

            my $content = $method_mock_files{$cache_file};
            is( $content, "0\n", 'Cache file contains correct content for decision 0' );
        };

        subtest 'write decision 1' => sub {
            my $cache_file = '/tmp/write_test_1.dat';

            my $result = $filter->write_cache( $cache_file, 1 );
            is( $result, 1, 'write_cache returns 1 on success' );

            my $content = $method_mock_files{$cache_file};
            is( $content, "1\n", 'Cache file contains correct content for decision 1' );
        };

        subtest 'write truthy value' => sub {
            my $cache_file = '/tmp/write_test_truthy.dat';

            my $result = $filter->write_cache( $cache_file, 'truthy' );
            is( $result, 1, 'write_cache returns 1 on success' );

            my $content = $method_mock_files{$cache_file};
            is( $content, "1\n", 'Truthy value normalized to 1' );
        };

        subtest 'write falsy value' => sub {
            my $cache_file = '/tmp/write_test_falsy.dat';

            my $result = $filter->write_cache( $cache_file, '' );
            is( $result, 1, 'write_cache returns 1 on success' );

            my $content = $method_mock_files{$cache_file};
            is( $content, "0\n", 'Falsy value normalized to 0' );
        };

        subtest 'overwrite existing cache' => sub {
            my $cache_file = '/tmp/write_test_overwrite.dat';
            $method_mock_files{$cache_file} = "old content\n";

            my $result = $filter->write_cache( $cache_file, 1 );
            is( $result, 1, 'write_cache returns 1 on success' );

            my $content = $method_mock_files{$cache_file};
            is( $content, "1\n", 'Cache file was overwritten with new content' );
        };
    };
};

subtest 'Preserve previous selections functionality' => sub {

    subtest 'preserves previously selected servers' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/previous_round.cache';
        my $current_cache  = '/tmp/current_round.cache';

        # Set up previous cache with server selected (1)
        $preserve_mock_files{$previous_cache} = "1\n";

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 10000,
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should preserve previous selection (1)
        is( $result, !!1, 'Previously selected server remains selected' );

        # Verify current cache was updated with preserved decision
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content if defined $cached_content;
        is( $cached_content, '1', 'Current cache reflects preserved selection' );
    };

    subtest 'applies new random sampling to previously unselected servers' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/previous_unselected.cache';
        my $current_cache  = '/tmp/current_unselected.cache';

        # Set up previous cache with server not selected (0)
        $preserve_mock_files{$previous_cache} = "0\n";

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 25000,             # High probability for testing
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should apply new random sampling (could be 0 or 1)
        ok( $result == 0 || $result == 1, 'Previously unselected server gets new random decision' );

        # Verify current cache was updated with new decision
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content;
        is( int($cached_content), int($result), 'Current cache reflects new random decision' )
          or diag explain $preserve_mock_files{$current_cache}, $result;
    };

    subtest 'handles servers not in previous population' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/no_previous.cache';
        my $current_cache  = '/tmp/new_server.cache';

        # Previous cache file doesn't exist (server wasn't in previous population)

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 25000,             # High probability for testing
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should apply new random sampling for new server
        ok( $result == 0 || $result == 1, 'New server in population gets random decision' );

        # Verify current cache was created with decision
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content;
        is( int($cached_content), int($result), 'Current cache created for new server' )
          or diag explain %preserve_mock_files, $result;
    };

    subtest 'server available for resampling when preserve_previous_selections is false' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/ignore_previous.cache';
        my $current_cache  = '/tmp/ignore_current.cache';

        # Set up previous cache with server selected (1)
        $preserve_mock_files{$previous_cache} = "1\n";

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 1000,
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 0                  # Explicitly false
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should ignore previous cache and generate new random decision
        ok( $result == 0 || $result == 1, 'Server available for resampling when preserve_previous_selections is false' );

        # Verify current cache was updated with new decision
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content;
        is( int($cached_content), int($result), 'Current cache reflects new random decision' )
          or diag explain %preserve_mock_files, $result;
    };

    subtest 'server available for resampling when previous_cache_files not provided' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $current_cache = '/tmp/no_previous_specified.cache';

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 1000,
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            preserve_previous_selections => 1                 # True but no previous_cache_files
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        ok( $result eq !!0 || $result eq !!1, 'Standard random decision when no previous_cache_files' );

        # Verify current cache was updated
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content if defined $cached_content;

        # Convert result to match expected format for cache content comparison
        my $expected_cache_content = ( $result eq !!1 ) ? "1" : "0";
        is( $cached_content, $expected_cache_content, 'Current cache created with random decision' )
          or diag "Cache content: '$cached_content', Result: '$result', Cache files: " . explain( \%preserve_mock_files );
    };

    subtest 'current cache takes precedence over preserve logic' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/precedence_previous.cache';
        my $current_cache  = '/tmp/precedence_current.cache';

        # Set up previous cache with server selected (1)
        $preserve_mock_files{$previous_cache} = "1\n";

        # Set up current cache with different decision (0)
        $preserve_mock_files{$current_cache} = "0\n";

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 10000,
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should return current cache value, ignoring preserve logic
        is( $result, !!0, 'Current cache takes precedence over preserve logic' );
    };

    subtest 'invalid previous cache content handled gracefully' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        my $previous_cache = '/tmp/invalid_previous.cache';
        my $current_cache  = '/tmp/graceful_current.cache';

        # Set up previous cache with invalid content
        $preserve_mock_files{$previous_cache} = "invalid\n";

        my $config = {
            rule                         => { true => 1 },
            sample_size                  => 25000,             # High probability for testing
            fleet_size                   => 50000,
            cache_file                   => $current_cache,
            previous_cache_files         => [$previous_cache],
            preserve_previous_selections => 1
        };

        my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
        my $result = $filter->is_allowed();

        # Should treat invalid previous cache as "not previously selected" and apply random sampling
        ok( $result eq !!0 || $result eq !!1, 'Invalid previous cache triggers new random decision' );

        # Verify current cache was updated
        ok( exists $preserve_mock_files{$current_cache}, 'Current cache file was created' );
        my $cached_content = $preserve_mock_files{$current_cache};
        chomp $cached_content if defined $cached_content;

        # Convert result to match expected format for cache content comparison
        my $expected_cache_content = ( $result eq !!1 ) ? "1" : "0";
        is( $cached_content, $expected_cache_content, 'Current cache created despite invalid previous cache' )
          or diag explain %preserve_mock_files, $result;
    };

    subtest 'multi-round population sub-sampling with preserved selections' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        # Simulate a population sub-sampling scenario:
        # Round 1: Select 1000 out of 50000 servers
        # Round 2: Preserve Round 1 selections + sub-sample from previously disabled and new servers (target: 10000 total)

        my $round1_cache = '/tmp/rollout_round1.cache';
        my $round2_cache = '/tmp/rollout_round2.cache';

        # Simulate multiple servers with their Round 1 decisions
        my @servers = (
            { id => 'server001', round1 => 1 },        # Previously selected
            { id => 'server002', round1 => 0 },        # Previously not selected
            { id => 'server003', round1 => 1 },        # Previously selected
            { id => 'server004', round1 => 0 },        # Previously not selected
            { id => 'server005', round1 => undef },    # New server (not in round 1)
        );

        my %round2_results;

        for my $server (@servers) {
            my $server_round1_cache = "/tmp/rollout_$server->{id}_round1.cache";
            my $server_round2_cache = "/tmp/rollout_$server->{id}_round2.cache";

            # Set up Round 1 cache if server participated
            if ( defined $server->{round1} ) {
                $preserve_mock_files{$server_round1_cache} = "$server->{round1}\n";
            }

            my $config = {
                rule                         => { true => 1 },
                sample_size                  => 10000,                  # Total target for Round 2
                fleet_size                   => 50000,
                cache_file                   => $server_round2_cache,
                previous_cache_files         => [$server_round1_cache],
                preserve_previous_selections => 1
            };

            my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
            my $result = $filter->is_allowed();

            $round2_results{ $server->{id} } = $result;

            # Verify behavior based on Round 1 decision
            if ( defined $server->{round1} && $server->{round1} == 1 ) {
                is( $result, !!1, "Server $server->{id}: Previously selected server remains selected" );
            }
            else {
                ok( $result eq !!0 || $result eq !!1, "Server $server->{id}: Gets new random decision" );
            }

            # Verify cache was updated
            ok( exists $preserve_mock_files{$server_round2_cache}, "Server $server->{id}: Round 2 cache file was created" );
            my $cached_content = $preserve_mock_files{$server_round2_cache};
            chomp $cached_content if defined $cached_content;

            # Convert result to match expected format for cache content comparison
            my $expected_cache_content = ( $result eq !!1 ) ? "1" : "0";
            is( $cached_content, $expected_cache_content, "Server $server->{id}: Round 2 cache reflects decision" )
              or diag explain %preserve_mock_files, $result;
        }

        # At minimum, previously selected servers should remain selected
        my $preserved_count = 0;
        my $total_selected  = 0;

        for my $server (@servers) {
            if ( $round2_results{ $server->{id} } eq !!1 ) {
                $total_selected++;
                if ( defined $server->{round1} && $server->{round1} == 1 ) {
                    $preserved_count++;
                }
            }
        }

        note("Preserved selections: $preserved_count");
        note("Total selected in Round 2: $total_selected");

        # All previously selected servers should be preserved
        is( $preserved_count, 2, 'All previously selected servers preserved' );
    };

    subtest 'two-round population sub-sampling with fleet size change' => sub {

        # Mock file operations to avoid real file system access
        my %preserve_mock_files;
        my $preserve_mock_slurper = Test::MockModule->new('Cpanel::Slurper');
        my $preserve_mock_writer  = Test::MockModule->new('Cpanel::FileUtils::Write');

        $preserve_mock_slurper->redefine(
            'read' => sub {
                my ($file) = @_;
                return $preserve_mock_files{$file} if exists $preserve_mock_files{$file};
                die "No such file or directory: $file";
            }
        );

        $preserve_mock_writer->redefine(
            'overwrite' => sub {
                my ( $file, $content, $perms ) = @_;
                $preserve_mock_files{$file} = $content;
                return 1;
            }
        );

        # Simulate a two-round population sub-sampling scenario with realistic fleet sizes:
        # Round 1: Select 10000 out of 44000 servers (sample_size: 10000, fleet_size: 44000)
        # Round 2: Preserve Round 1 + sub-sample from previously disabled and new servers with smaller fleet (sample_size: 10000, fleet_size: 29500)

        my @servers = (
            { id => 'server001', round1 => 1 },        # Selected in round 1
            { id => 'server002', round1 => 0 },        # Not selected in round 1
            { id => 'server003', round1 => 1 },        # Selected in round 1
            { id => 'server004', round1 => 0 },        # Not selected in round 1
            { id => 'server005', round1 => undef },    # New server (not in round 1)
        );

        my %round2_results;

        for my $server (@servers) {
            my $server_round1_cache = "/tmp/rollout2_$server->{id}_round1.cache";
            my $server_round2_cache = "/tmp/rollout2_$server->{id}_round2.cache";

            # Set up Round 1 cache if server participated
            if ( defined $server->{round1} ) {
                $preserve_mock_files{$server_round1_cache} = "$server->{round1}\n";
            }

            # Round 2 configuration: smaller fleet size (29500) with same sample size (10000)
            # Fleet reduced due to company fleet changes (servers removed/decommissioned)
            my $config = {
                rule                         => { true => 1 },
                sample_size                  => 10000,                  # Same target as Round 1
                fleet_size                   => 29500,                  # Smaller fleet (was 44000)
                cache_file                   => $server_round2_cache,
                previous_cache_files         => [$server_round1_cache],
                preserve_previous_selections => 1
            };

            my $filter = Cpanel::Plugins::Components::Rules::Random->new($config);
            my $result = $filter->is_allowed();

            $round2_results{ $server->{id} } = $result;

            # Verify behavior based on Round 1 decision
            if ( defined $server->{round1} && $server->{round1} == 1 ) {
                is( $result, !!1, "Server $server->{id}: Previously selected server remains selected in Round 2" );
            }
            else {
                ok( $result eq !!0 || $result eq !!1, "Server $server->{id}: Gets new random decision in Round 2" );
            }

            # Verify cache was updated
            ok( exists $preserve_mock_files{$server_round2_cache}, "Server $server->{id}: Round 2 cache file was created" );
            my $cached_content = $preserve_mock_files{$server_round2_cache};
            chomp $cached_content if defined $cached_content;

            # Convert result to match expected format for cache content comparison
            my $expected_cache_content = ( $result eq !!1 ) ? "1" : "0";
            is( $cached_content, $expected_cache_content, "Server $server->{id}: Round 2 cache reflects decision" )
              or diag explain %preserve_mock_files, $result;
        }

        # Analyze results
        my $preserved_count = 0;
        my $total_selected  = 0;
        my $newly_selected  = 0;

        for my $server (@servers) {
            if ( $round2_results{ $server->{id} } eq !!1 ) {
                $total_selected++;

                # Check if this server was selected in round 1
                if ( defined $server->{round1} && $server->{round1} == 1 ) {
                    $preserved_count++;
                }
                else {
                    $newly_selected++;
                }
            }
        }

        note("Round 2 Results with fleet_size: 29500 (was 44000), sample_size: 10000:");
        note("Preserved selections from Round 1: $preserved_count");
        note("Newly selected in Round 2: $newly_selected");
        note("Total selected in Round 2: $total_selected");

        # All previously selected servers should be preserved
        is( $preserved_count, 2, 'All previously selected servers preserved in Round 2' );

        # With smaller fleet size and same sample size, selection probability increases (10000/29500 = 33.9% vs 10000/44000 = 22.7%)
        # But this depends on randomness, so we just verify the preserve logic worked
        ok( $total_selected >= $preserved_count, 'Total selections includes at least all preserved servers' );
    };
};

done_testing;
