#!/usr/bin/perl

## no critic (ErrorHandling::RequireCheckingReturnValueOfEval);
## no critic (CodeLayout::ProhibitParensWithBuiltins);
## no critic (InputOutput::RequireCheckedSyscalls) ;

# Create and link workgroups needed to manage Office365 resource calendars.

use strict;
use warnings;
use autodie;

use Carp;
use CGI;
use DBI;
use Email::Valid;
use Getopt::Long::Descriptive;
use File::Temp ;
use IPC::Run qw/ run / ;
use Net::Remctl;
use Readonly;
use Template;
use Try::Tiny;

use Stanford::Schema::WebApps::SharedEmail;
use Stanford::WebApps::SharedEmail::Config qw(%CONFIG);
use Stanford::WebApps::SharedEmail::RequestForm;
use Stanford::WebApps::SharedEmail::Util qw(
    read_password
    refresh_krb5_cache
    remctl_link_workgroup
    link_workgroup_enabled
);
use Stanford::WorkgroupXML;
use Stanford::WorkgroupXML::Workgroup;


my $KERBEROS_CACHE ;
my $VERBOSE = 1;
my $DRY_RUN ;
my $ONLY_ONE ;


END {
    if ($KERBEROS_CACHE && (-f $KERBEROS_CACHE)) {
        progress("deleting Kerberos cache file '$KERBEROS_CACHE'");
    }
}

# ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### #
sub log_error {
    my ($msg) = @_;
    print {*STDERR} $msg . "\n";
    return;
}

sub progress {
    my ($msg) = @_;

    if ($VERBOSE) {
        print "progress: $msg\n";
    }
    return;
}

sub dryrun {
    my ($msg) = @_;
    print "dry0run: $msg\n";
    return;
}

sub krb_cache_setup {
    progress('starting run of shared-email-create-cal-wg');

    my $krb5_keytab = $CONFIG{'krb5_keytab'} ;

    # Set up our Kerberos credentials cache.
    my $fh ;
    ($fh, $KERBEROS_CACHE) = File::Temp::tempfile() ;
    close($fh) ;
    return refresh_krb5_cache($krb5_keytab, $KERBEROS_CACHE) ;
}

sub run_command {
    my (@command) = @_;

    # (From Russ)
    my ($out, $err);
    IPC::Run::run(\@command, q{>}, \$out, q{2>}, \$err);

    ## no critic (Variables::ProhibitPunctuationVars);
    ## no critic (ValuesAndExpressions::ProhibitMagicNumbers);
    return ($out, $err, $? >> 8);
}

sub create_wg {
    my ($uid, $sunetid) = @_ ;

    progress("creating workgroup for uid: $uid, sunetid: $sunetid");

    my $create_wg_successful = 0;

    my ($wgroup, $wgroup_admins, $wgroup_members);

    # Create an empty WorkgroupXML object
    try {
        $wgroup = Stanford::WorkgroupXML::Workgroup->new({
            url_base => $CONFIG{'shared_email_wxml_urlbase'},
            key      => $CONFIG{'shared_email_wxml_key'},
            cert     => $CONFIG{'shared_email_wxml_cert'},
        });
        $create_wg_successful = 1;
    };

    # Set basic attributes before creating the workgroup
    $wgroup->description(  'Read/write access to the ' . $uid
                         . ' Resource Mailbox'
    );
    $wgroup->privgroup(1);
    $wgroup->reusable(0);
    $wgroup->visibility(1);

    # Actually create the workgroup, then get our admin and member lists
    try {
        $wgroup->create('office365:' . $uid);
        $wgroup_admins = $wgroup->administrators();
        $wgroup_members = $wgroup->members();
        $wgroup_members->add_member($sunetid);
        $wgroup_admins->add_member($sunetid);

    } catch {
       print "$_\n";
    };

    # Add the stem owner as a workgroup admin
    try {
        $wgroup_admins->add_workgroup('workgroup:office365-owners');
        progress('"added workgroup admin workgroup:office365-owners');
    } catch {
        log_error('Failure adding workgroup:office365-' .
                  'to Workgroup office365:' .
                  $uid . ": $_"
            );
    }

    return $create_wg_successful;
}

sub set_wg_status_to_one {
    my ($dbh, $uid) = @_ ;

    my $uth = $dbh->prepare("UPDATE resources SET resources.wgrp_status = 1 " .
                            "WHERE resources.uid = '$uid'");
    $uth->execute();
    $uth->finish();

    progress("updated CRDB table: set $uid wgrp_status to indicate workgroup is now created");
    return ;
}


sub process {
    my ($number_to_process) = @_ ;

    # check for any newly created calendars that need workgroups

    my $host            = $CONFIG{'crdb_db_host'};
    my $db              = $CONFIG{'crdb_db_name'};
    my $userid          = $CONFIG{'crdb_db_user'};
    my $connection_info = "dbi:mysql:$db;$host";
    my $passwd          = read_password($CONFIG{'crdb_db_passwd_file'});

    # make connection to database
    my $dbh = DBI->connect($connection_info, $userid, $passwd);
    progress("made connection to database server $host");

    my ( $uid, $sunetid );

    # prepare and execute query
    my $query = 'SELECT resources.uid, resourceadmins.sunetid FROM `resources`, resourceadmins '
              . 'WHERE resources.id = resourceadmins.resource_id AND resources.wgrp_status = 0';
    my $sth = $dbh->prepare($query);
    $sth->execute();
    progress("ran SQL query $query");

    # assign fields to variables
    $sth->bind_col( 1, \$uid );
    $sth->bind_col( 2, \$sunetid );

    # loop through results and create workgroups
    my $total_processed = 0;
    my @uids_processed = () ;
    while($sth->fetch()) {
        progress('found result');

        my $SCHEMA;
        eval {
            $SCHEMA = Stanford::Schema::WebApps::SharedEmail->connect(\%CONFIG);
        };

        # Start connecting to outside stuff
        if ($DRY_RUN) {
            dryrun("creating workgroup for ($uid, $sunetid)");
        } else {
            progress("creating workgroup for ($uid, $sunetid)");
            my $create_wg_successful = create_wg($uid, $sunetid) ;

            if ($create_wg_successful) {
                progress("workgroup for ($uid, $sunetid) created successfully");
                set_wg_status_to_one($dbh, $uid);
                progress("updated wgrp_status for $uid");
            } else {
                progress("workgroup for ($uid, $sunetid) creation failed");
            }

        }

        ++$total_processed;
        push(@uids_processed, $uid);

        # If we want to process only one group, stop now.
        if ($ONLY_ONE && ($total_processed > 0)) {
            last ;
        }
    }

    $sth->finish();

    # Disconnect from database
    $dbh->disconnect;

    if ($total_processed == 0) {
        progress('no results found');
    } else {
        progress("$total_processed results found");
    }

    progress('finished the process routine');

    return ;
}


# ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### #

my ($opt, $usage) = describe_options(
    'shared-email-create-cal-wg %o <some-arg>',
    [ 'dry-run|n',  'dry-run mode', ],
    [ 'only-one|w', 'process only one CRDB workgroup', ],
    [],
    [ 'verbose|v',  'print extra stuff'            ],
    [ 'help',       'print usage message and exit', { shortcircuit => 1 } ],
    );

if ($opt->help) {
    print $usage->text ;
    exit 0 ;
}

if ($opt->dry_run) {
    $DRY_RUN = 1 ;
} else {
    $DRY_RUN = 0 ;
}

if ($opt->only_one) {
    $ONLY_ONE = 1 ;
} else {
    $ONLY_ONE = 0 ;
}

krb_cache_setup();
process();

progress('finished run of shared-email-create-cal-wg');
