The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Silki::Test::RealSchema;

use strict;
use warnings;

use lib 'inc';

use DBD::Pg;
use DBI;
use File::Slurp qw( read_file );
use Path::Class qw( dir file );
use Test::More;

sub import {
    eval {
        DBI->connect(
            'dbi:Pg:dbname=template1',
            q{}, q{}, {
                RaiseError => 1,
                PrintError => 0,
                PrintWarn  => 0,
            }
        );
    };

    if ($@) {
        Test::More::plan skip_all =>
            'Cannot connect to the template1 database with no username or password';
        exit 0;
    }

    if ( _database_exists() ) {
        _clean_tables();
    }
    else {
        _recreate_database();
    }

    require Silki::Config;

    # Need to explicitly override anything that might be found in an existing
    # config file
    Silki::Config->instance()->_set_database_name('SilkiTest');
    Silki::Config->instance()->_set_database_username(q{});
    Silki::Config->instance()->_set_database_password(q{});

    _seed_data();
}

sub _database_exists {
    my $dbh = eval {
        DBI->connect(
            'dbi:Pg:dbname=SilkiTest',
            q{}, q{}, {
                RaiseError         => 1,
                PrintError         => 0,
                PrintWarn          => 1,
                ShowErrorStatement => 1,
            },
        );
    };

    return if $@ || ! $dbh;

    my ($version_insert) = grep { /INSERT INTO "Version"/ } _ddl_statements();

    my ($expect_version) = $version_insert =~ /VALUES \((\d+)\)/;

    my $col = eval { $dbh->selectcol_arrayref( q{SELECT version FROM "Version"} ) };

    return $col && defined $col->[0] && $col->[0] == $expect_version;
}

sub _recreate_database {
    diag('Creating SilkiTest database');

    require Silki::DatabaseManager;

    my $man = Silki::DatabaseManager->new(
        db_name => 'SilkiTest',
        drop    => 1,
        quiet   => 1,
    );

    $man->update_or_install_db();
}

sub _clean_tables {
    my $dbh = DBI->connect(
        'dbi:Pg:dbname=SilkiTest',
        q{}, q{}, {
            RaiseError         => 1,
            PrintError         => 0,
            PrintWarn          => 1,
            ShowErrorStatement => 1,
        },
    );

    diag('Cleaning tables in existing SilkiTest database');

    my @tables;
    for my $stmt ( _ddl_statements() ) {
        next unless $stmt =~ /^CREATE TABLE (\S+)/;

        my $table = $1;
        next if $table eq q{"Version"};

        push @tables, $table;
    }

    $dbh->do( 'TRUNCATE ' . ( join ', ', @tables ) . ' CASCADE' );
}

{
    my @DDL;

    sub _ddl_statements {
        return @DDL if @DDL;

        my $file = dir( $INC{'Silki/Test/RealSchema.pm'} )->parent()->parent()
            ->parent()->parent()->parent()->file( 'schema', 'Silki.sql' );

        my $ddl = read_file( $file->resolve()->stringify() );

        for my $stmt ( split /\n\n+(?=^\S)/m, $ddl ) {
            $stmt =~ s/^--.+\n//gm;

            next unless $stmt =~ /^(?:CREATE|ALTER|INSERT)/;

            next if $stmt =~ /^CREATE DATABASE/;

            push @DDL, $stmt;
        }

        return @DDL;
    }
}

sub _seed_data {
    require Silki::SeedData;

    Silki::SeedData::seed_data();
}

1;