package Cpanel::Easy::Test::OptMod;

use strict;
use warnings;
no warnings qw(redefine);

sub new {
    my ( $class, $args ) = @_;

    die 'Arguments must be in a hash ref'                    if ref $args                 ne 'HASH';
    die '$easyconfig much be a HASH ref to test keys' . "\n" if ref $args->{'easyconfig'} ne 'HASH';
    die $args->{'file'} . ' does not exist' . "\n"           if !-e $args->{'file'};

    return bless {
        'easyconfig' => $args->{'easyconfig'},
        'file'       => $args->{'file'},
        'required'   => {
            'version' => 0,
            'name'    => 0,
        },
        'optional' => [
            qw{
              note desc ensurepkg
              src_cd2 hastargz meta
              url skip reverse
              configure depends dryrun
              dryrun_fails_fatal haspatch
              depend_fails_fatal when_i_am_off
              step
              }
        ],
        'errors' => {
            'required'        => [],
            'optional'        => [],
            'dependency_list' => [],
        },
    }, $class;
}

sub test_easyconfig {
    my ($self) = @_;
    my $file = $self->{'file'};

    foreach my $key ( keys %{ $self->{'easyconfig'} } ) {
        $self->{'required'}{$key}++ if exists $self->{'required'}{$key};
        $self->validate_step( $self->{'easyconfig'}{$key}, $file, ucfirst $key ) if ( $key eq 'step' ) or ( $key eq 'dryrun' );
        $self->validate_optional( $key, $file );
    }
    $self->validate_required($file);
    $self->dependency_list($file);
}

sub validate_optional {
    my ( $self, $key ) = @_;
    my $file = $self->{'file'};
    return if exists $self->{'required'}{$key};

    my $found = grep { $key eq $_ } @{ $self->{'optional'} };
    if ( !$found ) {
        push @{ $self->{'errors'}{'optional'} }, "'$key' is not a recognized key in file: $file";
    }

}

sub dependency_list {
    my ( $self, $file ) = @_;
    if ( open( my $fh, '<', $file ) ) {
        while ( my $line = <$fh> ) {
            if ( $line =~ /^(?:\#\s*use\s+(\S+)\;)/ ) {
                my $module = $1;
                push @{ $self->{'errors'}{'dependency_list'} }, 'use ' . $module . '; is commented out in file ' . $file;
            }
        }
        close $fh;
    }
}

sub validate_required {
    my ( $self, $file ) = @_;
    foreach my $key ( keys %{ $self->{'required'} } ) {
        push @{ $self->{'errors'}{'required'} }, $file . ' is missing required key: ' . $key if !$self->{'required'}{$key};
    }
}

sub validate_step {
    my ( $self, $step_hash, $file, $type ) = @_;
    foreach my $step_num ( keys %{$step_hash} ) {
        push @{ $self->{'errors'}{'required'} }, "Step number ($step_num) is not a number in file: $file" if $step_num !~ /^\d+(?:\.\d+)?$/;
        my $command = 0;
        my $name    = 0;
        foreach my $step_keys ( keys %{ $step_hash->{$step_num} } ) {
            $command++ if $step_keys eq 'command';
            $name++    if $step_keys eq 'name';
        }
        push @{ $self->{'errors'}{'required'} }, "$type number ($step_num) in $file is missing the 'name' key"   if !$name;
        push @{ $self->{'errors'}{'required'} }, "$type number ($step_num) in $file is missing the'command' key" if !$command;
    }
}

sub has_errors {
    my ($self) = @_;
    return 1 if $self->required_errors();
    return 1 if $self->optional_errors();
    return 1 if $self->dependency_errors();
    return;
}

sub required_errors {
    my ($self) = @_;
    return @{ $self->{'errors'}{'required'} };
}

sub optional_errors {
    my ($self) = @_;
    return @{ $self->{'errors'}{'optional'} };
}

sub dependency_errors {
    my ($self) = @_;
    return @{ $self->{'errors'}{'dependency_list'} };
}

1;
