#!/usr/bin/perl
use strict;
use warnings;
use perunServicesInit;
use perunServicesUtils;
use Time::Piece;

sub isExpired;

our $SERVICE_NAME     = "vsup_google_groups";
our $PROTOCOL_VERSION = "3.0.0";
my $SCRIPT_VERSION = "3.0.1";

perunServicesInit::init;
my $DIRECTORY = perunServicesInit::getDirectory;
my $data = perunServicesInit::getHashedHierarchicalData;

# Constants
our $A_F_GOOGLE_GROUP_DOMAIN;		*A_F_GOOGLE_GROUP_DOMAIN =			\'urn:perun:facility:attribute-def:def:googleGroupDomain';
our $A_R_GOOGLE_GROUP_NAME;				*A_R_GOOGLE_GROUP_NAME =		\'urn:perun:resource:attribute-def:def:googleGroupName';
our $A_R_GOOGLE_GROUP_DISPLAY_NAME;		*A_R_GOOGLE_GROUP_DISPLAY_NAME =\'urn:perun:resource:attribute-def:def:googleGroupDisplayName';
our $A_U_GOOGLE_GROUP_LOGIN;			*A_U_GOOGLE_GROUP_LOGIN =		\'urn:perun:user:attribute-def:def:login-namespace:vsup';
our $A_U_FIRST_NAME; 			*A_U_FIRST_NAME =			\'urn:perun:user:attribute-def:core:firstName';
our $A_U_LAST_NAME; 			*A_U_LAST_NAME =			\'urn:perun:user:attribute-def:core:lastName';
our $A_U_ARTISTIC_FIRST_NAME; 	*A_U_ARTISTIC_FIRST_NAME = 	\'urn:perun:user:attribute-def:def:artisticFirstName';
our $A_U_ARTISTIC_LAST_NAME; 	*A_U_ARTISTIC_LAST_NAME = 	\'urn:perun:user:attribute-def:def:artisticLastName';
our $A_EXPIRATION_KOS;  *A_EXPIRATION_KOS = \'urn:perun:user:attribute-def:def:expirationKos';
our $A_EXPIRATION_DC2;  *A_EXPIRATION_DC2 = \'urn:perun:user:attribute-def:def:expirationDc2';
our $A_EXPIRATION_MANUAL;  *A_EXPIRATION_MANUAL = \'urn:perun:user:attribute-def:def:expirationManual';

# Global data structure

# $users->{$login}->{ATTR} = $attrValue;
our $users = {};
# $groups->{name}->{"displayName"} = nice name of a group;
# $groups->{name}->{"members"}->{$login} = 1;
our $groups = {};

my $domainName = $data->getFacilityAttributeValue(attrName => $A_F_GOOGLE_GROUP_DOMAIN);

if (!defined($domainName)) {
	exit 1;
}

#
# AGGREGATE DATA
#
# FOR EACH RESOURCE
foreach my $resourceId ($data->getResourceIds()) {

	my $groupName = $data->getResourceAttributeValue(resource => $resourceId, attrName => $A_R_GOOGLE_GROUP_NAME);
	my $groupDisplayName = $data->getResourceAttributeValue(resource => $resourceId, attrName => $A_R_GOOGLE_GROUP_DISPLAY_NAME);

	if (defined $groupName and length $groupName) {
		unless(exists $groups->{$groupName}) {
			$groups->{$groupName}->{"displayName"} = $groupDisplayName;
			$groups->{$groupName}->{"members"} = {};
		}
	}

	foreach my $memberId ($data->getMemberIdsForResource(resource => $resourceId)) {

		my $login = $data->getUserAttributeValue(member => $memberId, attrName => $A_U_GOOGLE_GROUP_LOGIN);
		my $artisticFirstName = $data->getUserAttributeValue(member => $memberId, attrName => $A_U_ARTISTIC_FIRST_NAME);
		my $firstName = $data->getUserAttributeValue(member => $memberId, attrName => $A_U_FIRST_NAME);
		my $artisticLastName = $data->getUserAttributeValue(member => $memberId, attrName => $A_U_ARTISTIC_LAST_NAME);
		my $lastName = $data->getUserAttributeValue(member => $memberId, attrName => $A_U_LAST_NAME);
		my $expirationKOS = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_KOS);
		my $expirationDC2 = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_DC2);
		my $expirationManual = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_MANUAL);

		# create user entry
		$users->{$login}->{$A_U_FIRST_NAME} = ($artisticFirstName || ($firstName || ''));
		$users->{$login}->{$A_U_LAST_NAME} = ($artisticLastName || ($lastName || ''));
		$users->{$login}->{"suspended"} = (isExpired($expirationKOS, $expirationDC2, $expirationManual) == 1) ? "suspended" : "";

		# put member in a group
		if (defined $groupName and length $groupName) {
			$groups->{$groupName}->{"members"}->{$login."\@".$domainName} = 1;
		}

	}

}

#
# PRINT DOMAIN FILE
#
my $fileNameDomain = $DIRECTORY . "vsup_google_groups_domain";
open FILE, ">$fileNameDomain" or die "Cannot open $fileNameDomain: $! \n";
print FILE $domainName;
close(FILE) or die "Cannot close $fileNameDomain: $! \n";

#
# PRINT USERS DATA FILE
#
my $usersFileName = "$DIRECTORY/$::SERVICE_NAME"."_users.csv";
open FILE,">$usersFileName" or die "Cannot open $usersFileName: $! \n";
binmode FILE, ":utf8";

my @keys = sort keys %{$users};
for my $key (@keys) {
	print FILE $key . "\@" . $domainName . ";" . $users->{$key}->{$A_U_FIRST_NAME} . ";" . $users->{$key}->{$A_U_LAST_NAME} . ";" . $users->{$key}->{"suspended"} . "\n";
}
close(FILE) or die "Cannot close $usersFileName: $! \n";

#
# PRINT GROUPS DATA FILE
#
my $groupsFileName = "$DIRECTORY/$::SERVICE_NAME"."_groups.csv";
open FILE,">$groupsFileName" or die "Cannot open $groupsFileName: $! \n";
binmode FILE, ":utf8";

my @groupKeys = sort keys %{$groups};
for my $key (@groupKeys) {
	my @userKeys = sort keys %{$groups->{$key}->{"members"}};
	print FILE $key . ";" . $groups->{$key}->{"displayName"} . ";" . join(',', @userKeys) . "\n";
}
close(FILE) or die "Cannot close $groupsFileName: $! \n";

perunServicesInit::finalize;

#
# Calculate if user is expired or not.
#
# 1. param - expiration in KOS (studies)
# 2. param - expiration in DC2 (employees)
# 3. param - manually set expiration
#
# Returns 1 if expired, 0 if not or can't be determined
#
sub isExpired() {

	# read input
	my $expirationKos = shift;
	my $expirationDc2 = shift;
	my $expirationMan = shift;
	# parse to time or undef
	my $expirationKosTime = ($expirationKos) ? Time::Piece->strptime($expirationKos,"%Y-%m-%d") : undef;
	my $expirationDc2Time = ($expirationDc2) ? Time::Piece->strptime($expirationDc2,"%Y-%m-%d") : undef;
	my $expirationManTime = ($expirationMan) ? Time::Piece->strptime($expirationMan,"%Y-%m-%d") : undef;

	my @expirations = ();
	if (defined $expirationKosTime) { push(@expirations, $expirationKosTime->epoch); }
	if (defined $expirationDc2Time) { push(@expirations, $expirationDc2Time->epoch); }
	if (defined $expirationManTime) { push(@expirations, $expirationManTime->epoch); }

	# sort all expirations
	my @sorted_expirations = sort { $a <=> $b } @expirations;

	my $latest_expiration = $sorted_expirations[$#sorted_expirations];
	my $currentDate = Time::Piece->strptime(localtime->ymd,"%Y-%m-%d");

	if (!defined $expirationKos and !defined $expirationDc2 and !defined $expirationMan) {
		# if no expiration set in source data - take as "never"
		return 0;
	}

	# Add time 23:59:59 to the date, since we want accounts to be active on the last day
	$latest_expiration = $latest_expiration + 86399;

	if ($latest_expiration > $currentDate->epoch) {
		# not expired yet
		return 0;
	}

	# is expired
	return 1;

}
