use strict;
use warnings;
use Test::More;
use Time::Local qw( timegm );
use POSIX qw( strftime );

use Data::ShortNameProvider;

my %args = ( max_name_length => 32 );

# style failure cases
ok( !eval { Data::ShortNameProvider->new( ) },
    'Failed to load without a max_name_length' );
like(
    $@,
    qr{^Missing required arguments: max_name_length },
    '... expected error message'
);

ok( !eval { Data::ShortNameProvider->new( %args, style => 'not_a_style' ) },
    'Failed to load style class' );
like(
    $@,
    qr{^Can't locate Data/ShortNameProvider/Style/not_a_style\.pm },
    '... expected error message'
);

ok( !eval { Data::ShortNameProvider->new( %args, style => 'Test::More' ) },
    'Bad style class' );
like(
    $@,
    qr/^Test::More does not implement the Data::ShortNameProvider::Role::Style role /,
    '... expected error message'
);

# test the same style in different ways
for my $style (qw( Basic Data::ShortNameProvider::Style::Basic )) {

    for my $limit ( 0 .. 1 ) {
        my $v  = int rand 20;
        my $l  = $limit && 20 + int rand 20;
        my $p  = join '', map chr( 97 + rand 26 ), 0 .. rand 4;
        my $n  = join '', map chr( 65 + rand 26 ), 0 .. rand 5;
        my $t  = time - 5e5 + int rand 1e6;
        my $T  = timegm 0, 0, 0, ( gmtime $t )[ 3 .. 6 ];
        my $ts = strftime '%y%m%d', gmtime $t;
        %args = (
            style           => $style,
            max_name_length => $l,
            timestamp_epoch => $t,

            # Basic-specific arguments
            prefix  => $p,
            version => $v,
        );

        # failing tests
        ok( !eval { Data::ShortNameProvider->new( %args, version => 'a' ) },
            'non-numeric version' );
        like(
            $@,
            qr/^isa check for "version" failed: 'a' is not a integer /,
            '... expected error message'
        );

        # passing tests
        my $np = Data::ShortNameProvider->new(%args);

        # type checking
        isa_ok( $np,           'Data::ShortNameProvider' );
        isa_ok( $np->provider, 'Data::ShortNameProvider::Style::Basic' );
        is( $np->style, 'Data::ShortNameProvider::Style::Basic', 'style' );

        # delegated stuff
        is( $np->timestamp_epoch,           $t, 'timestamp_epoch (main)' );
        is( $np->provider->timestamp_epoch, $t, 'timestamp_epoch (style)' );

        # short names
        my $sn = $np->generate_name($n);
        is( $sn, "$p${v}_${ts}__$n", "'$sn' is a short name for '$n'" );

        ok( $np->is_generated_name($sn),    "'$sn' was generated by us" );
        ok( !$np->is_generated_name('foo'), "'foo' was NOT generated by us" );

        # parse names
        diag $np->provider->parsing_regexp;

        # via the provider
        ok( !$np->provider->parse_generated_name('foo'), "can't parse 'foo'" );
        my $hash = $np->provider->parse_generated_name($sn);
        is_deeply(
            $hash,
            {
                prefix          => $p,
                version         => $v,
                timestamp       => $ts,
                timestamp_epoch => $T,
                name            => $n,
            },
            "parsed '$sn' (style)"
        );
        is( $np->style->new($hash)->generate_name('bar'),
            "$p${v}_${ts}__bar", "generate a short name for 'bar' (style)" );

        # via the main class delegation
        ok( !$np->parse_generated_name('foo'), "can't parse 'foo'" );
        $hash = $np->parse_generated_name($sn);
        is_deeply(
            $hash,
            {
                style           => 'Data::ShortNameProvider::Style::Basic',
                max_name_length => $l,
                prefix          => $p,
                version         => $v,
                timestamp       => $ts,
                timestamp_epoch => $T,
                name            => $n,
            },
            "parsed '$sn' (main)"
        );
        is(
            Data::ShortNameProvider->new($hash)->generate_name('bar'),
            "$p${v}_${ts}__bar",
            "generate a short name for 'bar' (main)"
        );

        # error case
        $n = join '', map chr( 65 + rand 26 ), 1 .. 40;
        if ($limit) {
            ok( !eval { $np->generate_name($n) }, "$n is too long" );
            like(
                $@,
                qr/^$p${v}_${ts}__$n \(provided by Data::ShortNameProvider::Style::Basic\) is longer than the $l characters limit /,
                '... expected error message'
            );
        }
        else {
            ok( eval { $np->generate_name($n) }, "$n has no length limit" );
        }
    }

}

done_testing;
