#! /usr/bin/env perl

use strict;
use warnings;
use Hydra::Schema;
use Hydra::Helper::Nix;
use Hydra::Model::DB;
use File::Slurper qw(read_text);
use SQL::SplitStatement;
use List::Util qw(max);

my $db = Hydra::Model::DB->new();
my $dbh = $db->storage->dbh;
$dbh->{RaiseError} = 1;

my $home = getHydraHome;

my $sql_splitter = SQL::SplitStatement->new;

# Figure out the target schema version.
my $maxSchemaVersion = max (map { /.*\/upgrade-(\d.*)\.sql/; $1 } (glob "$home/sql/migrations/upgrade-[0-9]*.sql")) || 1;

# Check whether the database has been initialised.  If not, load the
# schema.
my @tables = $dbh->tables;
if (! grep { /SchemaVersion/i } @tables) {
    print STDERR "initialising the Hydra database schema...\n";
    my $schema = read_text(
        $dbh->{Driver}->{Name} eq 'Pg' ? "$home/sql/hydra.sql" :
        die "unsupported database type $dbh->{Driver}->{Name}\n");
    my @statements = $sql_splitter->split($schema);
    eval {
        $dbh->begin_work;
        $dbh->do($_) foreach @statements;
        $db->resultset('SchemaVersion')->create({version => $maxSchemaVersion});
        $dbh->commit;
    };
    die "schema initialisation failed: $@\n" if $@;
    exit 0;
}

# Get the current schema version.
my @versions = $db->resultset('SchemaVersion')->all;
die "couldn't get Hydra schema version!" if scalar @versions != 1;
my $schemaVersion = $versions[0]->version;

if ($schemaVersion <= 60) {
    print STDERR <<QUOTE;
WARNING: Schema version 62 and 63 make nullable jobset_id fields on
         Builds and Jobs non-nullable. On big Hydra servers, this
         migration will take many hours. Because of that, the
         migration is not automatic, and must be performed manually.

         To backfill these IDs, run: hydra-backfill-ids
QUOTE
}

for (my $n = $schemaVersion; $n < $maxSchemaVersion; $n++) {
    my $m = $n + 1;
    print STDERR "upgrading Hydra schema from version $n to $m\n";
    my $schema = read_text("$home/sql/migrations/upgrade-$m.sql");
    my @statements = $sql_splitter->split($schema);
    eval {
        $dbh->begin_work;
        sub run_ {
            my ($stm) = @_;
            print STDERR "executing SQL statement: $stm\n";
            $dbh->do($_);
        }
        run_($_) foreach @statements;
        $db->resultset('SchemaVersion')->update({version => $m});
        $dbh->commit;
    };
    die "schema upgrade failed: $@\n" if $@;
}

my @usersWithSha1s = $db->resultset('Users')->search(\['LENGTH(password) = 40 AND password ~ \'^[0-9a-f]{40}$\'']);
if (scalar(@usersWithSha1s) > 0) {
    print STDERR "upgrading user passwords from sha1\n";
    for my $user (@usersWithSha1s) {
        print STDERR " * " . $user->username . "\n";
        $user->setPassword($user->password);
    }
}
