use strict;
use warnings;
use English;
use File::Temp qw(tempdir); # in core since perl 5.6.1
use File::Copy qw(cp);
use File::Path qw(make_path);

sub check_fakechroot_running() {
    my $content = `FAKECHROOT_DETECT=1 sh -c "echo This should not be printed"`;
    my $result = 0;
    if ($content =~ /^fakechroot [0-9.]+\n$/) {
        $result = 1;
    }
    return $result;
}

sub test_setup() {
    if (length $ENV{TEST_DPKG_ROOT}) {
        print STDERR "test_setup() with DPKG_ROOT\n";
        $ENV{DPKG_ROOT} = tempdir( CLEANUP => 1 );
        return;
    }

    if ( !check_fakechroot_running ) {
	print STDERR "you have to run this script inside fakechroot and fakeroot:\n";
	print STDERR ("    fakechroot fakeroot perl $PROGRAM_NAME" . (join " ", @ARGV) . "\n");
	exit 1;
    }

    # Set up a chroot that contains everything necessary to run
    # deb-systemd-helper under fakechroot.
    print STDERR "test_setup() with fakechroot\n";

    my $tmpdir = tempdir( CLEANUP => 1 );
    mkdir "$tmpdir/dev";
    0 == system 'mknod', "$tmpdir/dev/null", 'c', '1', '3' or die "cannot mknod: $?";
    mkdir "$tmpdir/tmp";
    make_path("$tmpdir/usr/bin");
    make_path("$tmpdir/usr/lib/systemd/user");
    make_path("$tmpdir/lib/systemd/system/");
    make_path("$tmpdir/var/lib/systemd");
    make_path("$tmpdir/etc/systemd");
    if ( length $ENV{TEST_INSTALLED} ) {
        # if we test the installed deb-systemd-helper we copy it from the
        # system's installation
        cp "/usr/bin/deb-systemd-helper", "$tmpdir/usr/bin/deb-systemd-helper"
          or die "cannot copy: $!";
    }
    else {
        cp "$FindBin::Bin/../script/deb-systemd-helper",
          "$tmpdir/usr/bin/deb-systemd-helper"
          or die "cannot copy: $!";
    }

    # make sure that dpkg diversion messages are not translated
    local $ENV{LC_ALL} = 'C.UTF-8';
    # the chroot only needs to contain a working perl-base
    open my $fh, '-|', 'dpkg-query', '--listfiles', 'perl-base';

    while ( my $path = <$fh> ) {
        chomp $path;
        # filter out diversion messages in the same way that dpkg-repack does
        # https://git.dpkg.org/cgit/dpkg/dpkg-repack.git/tree/dpkg-repack#n238
        if ($path =~ /^package diverts others to: /) {
            next;
        }
        if ($path =~ /^diverted by [^ ]+ to: /) {
            next;
        }
        if ($path =~ /^locally diverted to: /) {
            next;
        }
        if ($path !~ /^\//) {
            die "path must start with a slash";
        }
        if ( -e "$tmpdir$path" ) {
            # ignore paths that were already created
            next;
        } elsif ( !-r $path ) {
            # if the host's path is not readable, assume it's a directory
            mkdir "$tmpdir$path" or die "cannot mkdir $path: $!";
        } elsif ( -l $path ) {
            symlink readlink($path), "$tmpdir$path";
        } elsif ( -d $path ) {
            mkdir "$tmpdir$path" or die "cannot mkdir $path: $!";
        } elsif ( -f $path ) {
            cp $path, "$tmpdir$path" or die "cannot cp $path: $!";
        } else {
            die "cannot handle $path";
        }
    }
    close $fh;

    $ENV{'SYSTEMCTL_INSTALL_CLIENT_SIDE'} = '1';

    # we run the chroot call in a child process because we need the parent
    # process remaining un-chrooted or otherwise it cannot clean-up the
    # temporary directory on exit
    my $pid = fork() // die "cannot fork: $!";
    if ( $pid == 0 ) {
        chroot $tmpdir or die "cannot chroot: $!";
        chdir "/"      or die "cannot chdir to /: $!";
        return;
    }
    waitpid($pid, 0);

    exit $?;
}

# reads in a whole file
sub slurp {
    open my $fh, '<', shift;
    local $/;
    <$fh>;
}

sub state_file_entries {
    my ($path) = @_;
    my $bytes = slurp($path);
    my $dpkg_root = $ENV{DPKG_ROOT} // '';
    return map { "$dpkg_root$_" } split("\n", $bytes);
}

my $dsh = '';
if ( length $ENV{TEST_INSTALLED} ) {
    # if we are to test the installed version of deb-systemd-helper then even
    # in DPKG_ROOT mode, we want to run /usr/bin/deb-systemd-helper
    $dsh = "/usr/bin/deb-systemd-helper";
} else {
    if ( length $ENV{TEST_DPKG_ROOT} ) {
        # when testing deb-systemd-helper from source, then in DPKG_ROOT mode,
        # we take the script from the source directory
        $dsh = "$FindBin::Bin/../script/deb-systemd-helper";
    } else {
        $dsh = "/usr/bin/deb-systemd-helper";
    }
}
$ENV{'DPKG_MAINTSCRIPT_PACKAGE'} = 'deb-systemd-helper-test';

sub dsh {
    return system($dsh, @_);
}

sub _unit_check {
    my ($cmd, $cb, $verb, $unit, %opts) = @_;

    my $retval = dsh($opts{'user'} ? '--user' : '--system', $cmd, $unit);

    isnt($retval, -1, 'deb-systemd-helper could be executed');
    ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal');
    $cb->($retval >> 8, 0, "random unit file '$unit' $verb $cmd");
}

sub is_enabled { _unit_check('is-enabled', \&is, 'is', @_) }
sub isnt_enabled { _unit_check('is-enabled', \&isnt, 'isnt', @_) }

sub is_debian_installed { _unit_check('debian-installed', \&is, 'is', @_) }
sub isnt_debian_installed { _unit_check('debian-installed', \&isnt, 'isnt', @_) }

1;
