package Ark::Plugin::Session::Backend;
use strict;
use warnings;
use Ark 'Component';

has session_id => (
    is      => 'rw',
    isa     => 'Maybe[Str]',
    lazy    => 1,
    builder => 'get_session_id',
);

has session_data => (
    is      => 'rw',
    isa     => 'Maybe[HashRef]',
    lazy    => 1,
    default => sub {
        my $self = shift;
        return unless $self->session_id;
        $self->get_session_data( $self->session_id );
    },
);

has session_updated => (
    is      => 'rw',
    isa     => 'Bool',
    default => 0,
);

has uuid_model => (
    is  => 'rw',
    isa => 'Str',
);

has digest_model => (
    is  => 'rw',
    isa => 'Str',
);

has expire => (
    is      => "rw",
    isa     => "Int",
    default => 0,
);

has finalized => (
    is      => 'rw',
    isa     => 'Bool',
    default => 0,
);

after $_ => sub { shift->session_updated(1); }
    for qw/get set remove/;

before $_ => sub {
    die "session is already finalized. can't call set or remove method" if shift->finalized;
} for qw/set remove/;

no Ark;

sub get {
    my ($self, $key) = @_;
    my $data = $self->session_data or return;
    $data->{ $key };
}

sub set {
    my ($self, $key, $value) = @_;
    $self->initialize_session_data unless $self->session_data;
    $self->session_data->{ $key } = $value;
}

sub remove {
    my ($self, $key) = @_;
    return unless $self->session_data;
    delete $self->session_data->{ $key };
}

sub regenerate {
    my ($self) = @_;

    # ignore if session does not exists
    return unless $self->session_id;

    my $session_data = $self->session_data;
    $self->remove_session_data($self->session_id);

    $self->initialize_session_data;
    $self->set_session_data($self->session_id => $session_data);
    $self->session_data($session_data);
}

sub initialize_session_data {
    my $self = shift;

    my $uuid   = $self->uuid_model && $self->app->model( $self->uuid_model );
    my $digest = $self->digest_model && $self->app->model( $self->digest_model );

    unless ($uuid) {
        $self->ensure_class_loaded('Data::UUID');
        $uuid = Data::UUID->new;
    }

    unless ($digest) {
        $self->ensure_class_loaded('Digest::SHA1');
        $digest = Digest::SHA1->new;
    }

    $digest->add( $uuid->create );

    $self->set_session_id( $digest->hexdigest );
    $self->session_data({});
}

# State
sub get_session_id { }

sub set_session_id {
    my ($self, $sid) = @_;
    $self->session_id($sid);
}

sub remove_session_id { }
# sub extend_session_id { }


# Store
sub get_session_data { }
sub set_session_data { }
sub remove_session_data { }

sub finalize_session {
    my ($self, $res) = @_;

    if ($self->session_updated and my $sid = $self->session_id) {
        $self->set_session_data( $sid, $self->session_data );
    }
    $self->finalized(1);
}

1;
