package AccountManager::Tools;

use Mojo::Base -strict;

use Digest::SHA;
use Encode;
use English qw(-no_match_vars);
use List::Util qw(shuffle);
use List::MoreUtils qw(pairwise);
use MIME::Base64;
use Template;
use Template::Constants qw(:chomp);

use AccountManager::Template::Plugin::Quote;

sub encrypt {
    my ($string, $key) = @_;

    my @string_chars = split(//, $string);
    my @key_chars    = split(//, $key);

    return encode_base64(otp(\@string_chars, \@key_chars));
}

sub decrypt {
    my ($string, $key) = @_;

    my @string_chars = split(//, decode_base64($string));
    my @key_chars = split(//, $key);

    return otp(\@string_chars, \@key_chars);
}

sub otp {
    my ($string, $key) = @_;

    my @chars =
        pairwise { chr(ord($a) ^ ord($b)) }
        @$string,
        @$key;

    return join('', @chars);
}

# get SHA256 hash for a string
sub sha256_hash {
    my ($s) = @_;

    return Digest::SHA::sha256_base64($s);
}

sub generate_password {
    my ($size) = @_;

    # define alphabet
    my @uppers       = ('A' .. 'N', 'P' .. 'Z');
    my @lowers       = ('a' .. 'k', 'm' .. 'z');
    my @punctuations = (':', '!', '?', '&', '$', '=', '-', '#');
    my @numerics     = ('0' .. '9');
    my @all          = (@uppers, @lowers, @punctuations, @numerics);

    # start with a random character of each class
    my @chars = (
        $uppers[ rand @uppers ],
        $lowers[ rand @lowers ],
        $punctuations[ rand @punctuations ],
        $numerics[ rand @numerics ]
    );

    # complete with additional characters
    for my $i (1 .. $size - 4) {
        push(@chars, $all[ rand @all ]);
    }

    return join('', shuffle(@chars));
}

sub generate_secret {
    my ($size) = @_;

    # define alphabet
    my @lowers       = ('a' .. 'k', 'm' .. 'z');
    my @numerics     = ('0' .. '9');
    my @all          = (@lowers, @numerics);

    # fill characters list
    my @chars;
    for my $i (1 .. $size) {
        push(@chars, $all[ rand @all ]);
    }

    return join('', shuffle(@chars));
}

## Updates simpleSamlPhp authsources.php configuration file
sub update_ssp_authsources {
    my ($templates_dir, $output, $accounts) = @_;

    my $tt2 = Template->new({
        ENCODING     => 'utf8',
        PRE_CHOMP    => CHOMP_ONE,
        INCLUDE_PATH => [
            sprintf("%s/other", $templates_dir),
            sprintf("%s/accounts", $templates_dir),
        ],
    });

    $tt2->process(
        'accounts.php.tt2',
        { accounts => $accounts},
        $output,
        { binmode => ':utf8' }
    ) or die $tt2->error();
}

1;
__END__

=head1 NAME

AccountManager::Tools - Set of subroutines usefull for the Test Account manager

=head1 DESCRIPTION

The Test Account manager instanciates test accounts associated to a SAML Identity Provider.
This module gathers a set of usefull subroutines.

=head1 FUNCTIONS

=over

=item generate_password()

Returns a random password following some security guidelines.

=item update_ssp_authsources()

Update simpleSAMLphp authsources.php configuration file with the currently valid test accounts.

=back