#  Copyright 2018 - present MongoDB, Inc.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

use strict;
use warnings;
package MongoDB::_ServerSession;

# ABSTRACT: MongoDB Server Session object

use version;
our $VERSION = 'v1.999.0'; # TRIAL

use MongoDB::Error;

use Moo;
use UUID::URandom;
use Math::BigInt;
use MongoDB::_Types qw(
    Document
);
use Types::Standard qw(
    Maybe
    InstanceOf
    Int
);
use constant UUID_TYPE => 4;

use namespace::clean -except => 'meta';

#pod =attr session_id
#pod
#pod     $server_session->session_id;
#pod
#pod Returns the session id for this server session as a L<BSON::Bytes> object
#pod containing a binary UUID V4. For lower network usage, if not provided on
#pod initialisation this class will generate a new UUID instead of consulting the
#pod server for a new session id.
#pod
#pod =cut

has session_id => (
    is => 'lazy',
    isa => Document,
    builder => '_build_session_id',
);

sub _build_session_id {
    my ( $self ) = @_;
    my $uuid = BSON::Bytes->new(
        data => UUID::URandom::create_uuid(),
        subtype => UUID_TYPE,
    );
    return { id => $uuid };
}

#pod =attr last_use
#pod
#pod     $server_session->last_use;
#pod
#pod Returns the unix time that this server session was last used. Used for checking
#pod expiry of a server session. If undefined, then the session has (probably) not
#pod been used on the server.
#pod
#pod =cut

has last_use => (
    is => 'rwp',
    init_arg => undef,
    isa => Maybe[Int],
);

#pod =attr transaction_id
#pod
#pod     $server_session->transaction_id
#pod
#pod Returns the current transaction id for this server session. This is a ratcheted
#pod incrementing ID number, which when combined with the session id allows for
#pod retrying transactions in the correct order.
#pod
#pod =cut

has transaction_id => (
    is => 'rwp',
    init_arg => undef,
    default => sub { Math::BigInt->new('0') },
);

#pod =method update_last_use
#pod
#pod     $server_session->update_last_use;
#pod
#pod Updates the value of L</last_use> to the current unix time.
#pod
#pod =cut

sub update_last_use {
    my ( $self ) = @_;
    $self->_set_last_use( time() );
}

sub _is_expiring {
    my ( $self, $session_timeout ) = @_;

    # if session_timeout is undef, then sessions arent actually supported (this
    # value should be from logical_session_timeout_minutes).
    return 1 unless defined $session_timeout;

    my $timeout = time() - ( ( $session_timeout - 1 ) * 60 );

    # Undefined last_use means its never actually been used on the server
    return 1 if defined $self->last_use && $self->last_use < $timeout;
    return;
}

sub _increment_transaction_id {
    my $self = shift;
    $self->transaction_id->binc();
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

MongoDB::_ServerSession - MongoDB Server Session object

=head1 VERSION

version v1.999.0

=head1 SYNOPSIS

    use MongoDB::_ServerSession;

    my $server_session = MongoDB::_ServerSession->new;

=head1 DESCRIPTION

This class encapsulates the session id and last use of the session. For use
with L<MongoDB::ClientSession> for session based operations.

=head1 ATTRIBUTES

=head2 session_id

    $server_session->session_id;

Returns the session id for this server session as a L<BSON::Bytes> object
containing a binary UUID V4. For lower network usage, if not provided on
initialisation this class will generate a new UUID instead of consulting the
server for a new session id.

=head2 last_use

    $server_session->last_use;

Returns the unix time that this server session was last used. Used for checking
expiry of a server session. If undefined, then the session has (probably) not
been used on the server.

=head2 transaction_id

    $server_session->transaction_id

Returns the current transaction id for this server session. This is a ratcheted
incrementing ID number, which when combined with the session id allows for
retrying transactions in the correct order.

=head1 METHODS

=head2 update_last_use

    $server_session->update_last_use;

Updates the value of L</last_use> to the current unix time.

=head1 AUTHORS

=over 4

=item *

David Golden <david@mongodb.com>

=item *

Rassi <rassi@mongodb.com>

=item *

Mike Friedman <friedo@friedo.com>

=item *

Kristina Chodorow <k.chodorow@gmail.com>

=item *

Florian Ragwitz <rafl@debian.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2018 by MongoDB, Inc.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004

=cut
