package System::Introspector::Sudoers;
use Moo;

has sudoers_file => (
    is      => 'ro',
    default => sub { '/etc/sudoers' },
);

has hostname => (
    is      => 'ro',
    default => sub { scalar `hostname` },
);

sub gather {
    my ($self) = @_;
    my %file = $self->_gather_files($self->sudoers_file);
    return \%file;
}

sub _gather_files {
    my ($self, $file) = @_;
    open my $fh, '<', $file
        or return $file => { error => "Unable to read: $!" };
    my @lines = <$fh>;
    my %file = ($file => { body => join '', @lines });
    for my $line (@lines) {
        chomp $line;
        if ($line =~ m{^#include\s+(.+)$}) {
            my $inc_file = $self->_insert_hostname($1);
            %file = (%file, $self->_gather_files($inc_file));
        }
        elsif ($line =~ m{^#includedir\s+(.+)$}) {
            my $inc_dir = $self->_insert_hostname($1);
            %file = (%file, $self->_gather_from_dir($inc_dir));
        }
    }
    return %file;
}

sub _gather_from_dir {
    my ($self, $dir) = @_;
    opendir(my $dh, $dir);
    return $dir => { error => "Unable to read dir $dir: $!" }
        unless $dh;
    my %file;
    while (my $file = readdir $dh) {
        next if $file =~ m{\.} or $file =~ m{~$};
        %file = (%file, $self->_gather_files("$dir/$file"));
    }
    return %file;
}

sub _insert_hostname {
    my ($self, $value) = @_;
    my $hostname = $self->hostname;
    $value =~ s{\%h}{$hostname}g;
    return $value;
}

1;
