package SimpleFlake;
use 5.008001;
use strict;
use warnings;

use Time::HiRes qw(time);
use Math::BigInt lib => 'GMP';
use Bytes::Random::Secure qw(
  random_bytes random_bytes_base64 random_bytes_hex
);

our $VERSION = "0.09";

our $random;
our @map = ( 0 .. 9, "A" .. "Z", "a" .. "z" );

sub random {

    my ($class) = @_;

    unless ($random) {

        $random = Bytes::Random::Secure->new(
            Bits        => 64,
            NonBlocking => 1,
        );
    }

    return $random;
}

sub get_random_bits {

    my ( $class ) = @_;

    my $return = Math::BigInt->from_bin( unpack( 'B*', $class->random->bytes(8) ) );

    return $return;
}

sub get_millisecond_timestamp {

    my $epoch = 946702800;

    my $time = Math::BigInt->new( int( ( time - $epoch ) * 100_000_000 ) );
    return $time;
}

sub get_pid {

    return Math::BigInt->new($$);
}

sub get_flake {

    my $self = shift;

    my $timestamp = $self->get_millisecond_timestamp;
    my $random    = $self->get_random_bits;
    my $pid       = $self->get_pid;

    my $t = $timestamp->blsft(4) ;
    my $r =  $t->bior($pid);
    my $p = $t->blsft(32);
    my $y = $p->bior($random);
    my $a = base36encode($y->as_int);
    return $a;
}

sub base36encode {

    my $number = shift;

    my $output = "";
    my ( $q, $r );

    do {
        ( $q, $r ) = ( int( $number / 62 ), $number % 62 );
        $number /= 62;
        $output = $map[$r] . $output;
    } while ($q);

    return $output;
}

1;
__END__

=encoding utf-8

=head1 NAME

SimpleFlake - A perl implemantation of SimpleFlake. Inspired by https://github.com/SawdustSoftware/simpleflake

=head1 SYNOPSIS

    use SimpleFlake;

    my $hex_flake = SimpleFlake->get_flake;

=head1 DESCRIPTION

SimpleFlake is a unique ID Generation Module based on timestamp in milliseconds, the pid and a part of randomness

=head1 LICENSE

Copyright (C) Jens Gassmann - Software Entwicklung.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 AUTHOR

=over 1

=item Jens Gassmann E<lt>jg@gassmann.itE<gt>

=back

=cut