#!/usr/bin/env perl

# expire-sessions: Run regularly to remove old sessions (plus
# can set up data for 'log user out' admin functionality, and
# inactive user processing).

use v5.14;
use warnings;

BEGIN {
    use File::Basename qw(dirname);
    use File::Spec;
    my $d = dirname(File::Spec->rel2abs($0));
    require "$d/../setenv.pl";
}

use FixMyStreet::DB;
use Getopt::Long;
use List::Util qw(uniq);

GetOptions(
    # Update sessions to make sure all present in User objects
    'init' => \my $init,
);

my $rs = FixMyStreet::DB->resultset("Session")->search(undef, { cursor_page_size => 1000 });
my $now = time();
my $waste_cutoff = $now - 86400;

# Delete expired sessions (including from in User object)
# And update last active time of current sessions
while (my $session = $rs->next) {
    my $id = $session->id_code;
    my $user = $session->user;
    my $expires = $session->expires;
    if (!$expires || $expires < $now) {
        if ($user) {
            my $sessions = $user->get_extra_metadata('sessions');
            my @new_sessions = grep { $_ ne $id } @$sessions;
            update_user_sessions($user, \@new_sessions) if @new_sessions != @$sessions;
        }
        $session->delete;
    } elsif ($user && $init) {
        my $sessions = $user->get_extra_metadata('sessions');
        my @new_sessions = uniq @$sessions, $id;
        update_user_sessions($user, \@new_sessions) if @new_sessions != @$sessions;
    }
    if ($user) {
        update_user_last_active($user, $expires);
        $user->update;
    }

    next unless $session->in_storage;

    # Check old waste cache
    my $any = 0;
    my $data = $session->data;
    my $waste_data = $data->{waste};
    foreach (keys %$waste_data) {
        my $time = $waste_data->{$_}[0];
        if ($time < $waste_cutoff) {
            delete $waste_data->{$_};
            $any = 1;
        }
    }
    if ($any) {
        $session->data($data);
        $session->update;
    }
}

# ---

sub update_user_last_active {
    my ($user, $expires) = @_;
    return unless $expires;
    my $t = DateTime->from_epoch(epoch => $expires)->subtract(weeks => 4);
    $user->set_last_active($t) if !$user->last_active || $user->last_active < $t;
}

sub update_user_sessions {
    my ($user, $sessions) = @_;
    if (@$sessions) {
        $user->set_extra_metadata('sessions', $sessions);
    } else {
        $user->unset_extra_metadata('sessions');
    }
}
