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

use strict;
use warnings;
use autodie qw( :all );

use lib 'lib';

use MooseX::Types::Moose qw( Bool HashRef Str );
use Path::Class qw( dir file );

use Moose;
use MooseX::StrictConstructor;

extends 'Pg::DatabaseManager';

with 'MooseX::Getopt::Dashes';

has '+app_name' => (
    default => 'Silki',
);

has '+db_encoding' => (
    default => 'UTF-8',
);

has '+contrib_files' => (
    lazy    => 1,
    default => sub {
        $_[0]->sql_file() =~ /v[12]$/ ? [] : ['citext.sql'];
    },
);

has _existing_config => (
    traits  => ['NoGetopt'],
    is      => 'ro',
    isa     => HashRef[Str],
    lazy    => 1,
    builder => '_build_existing_config',
);

has seed => (
    is      => 'ro',
    isa     => Bool,
    default => 0,
    documentation =>
        'When this is true, a newly created database will be seeded with some initial required data. Defaults to false.',
);

has production => (
    is      => 'ro',
    isa     => Bool,
    default => 0,
    documentation =>
        'If true, this changes what data is seeded. In particular, only one wiki will be seeded instead of three.',
);

# If this isn't done these attributes end up interleaved with attributes from
# the parent class when --help is run.
__PACKAGE__->meta()->get_attribute('seed')->_set_insertion_order(20);
__PACKAGE__->meta()->get_attribute('production')->_set_insertion_order(21);

sub BUILD {
    my $self = shift;
    my $p    = shift;

    my $existing = $self->_existing_config();
    unless ( exists $p->{db_name} ) {
        die
            "No database name provided to the constructor and none can be found in an existing Silki config file."
            unless $existing->{name};

        $self->_set_db_name( $existing->{name} );
    }

    for my $attr (qw( username password host port )) {
        my $set = '_set_' . $attr;

        $self->$set( $existing->{$attr} )
            if defined $existing->{$attr};
    }

    return;
}

after update_or_install_db => sub {
    my $self = shift;

    $self->_seed_data() if $self->seed();
};

override '_connect_failure_message' => sub {
    my $self = shift;

    my $msg = super();

    $msg
        .= "\n  You can change connection info settings by passing arguments to 'perl Build.PL'\n";
    $msg .= "  See the INSTALL documentation for details.\n\n";

    return $msg;
};

sub _build_existing_config {
    my $self = shift;

    require Silki::Config;

    my $instance = Silki::Config->instance();

    return {} unless $instance->config_file();

    return {
        map {
            my $attr = 'database_' . $_;
            $instance->$attr() ? ( $_ => $instance->$attr() ) : ()
            } qw( name username password host port )
    };
}

sub _build_sql_file {
    return file( 'schema', 'Silki.sql' );
}

sub _build_migrations_dir {
    return dir( 'inc', 'migrations' );
}

sub _seed_data {
    my $self = shift;

    require Silki::Config;

    my $config = Silki::Config->instance();
    $config->_set_database_name( $self->db_name() );

    for my $key (qw( username password host port )) {
        if ( my $val = $self->$key() ) {
            my $set_meth = '_set_database_' . $key;

            $config->$set_meth($val);
        }
    }

    require Silki::SeedData;

    my $db_name = $self->db_name();
    $self->_msg("Seeding the $db_name database");

    Silki::SeedData::seed_data(
        production => $self->production(),
        verbose    => !$self->quiet()
    );
}

1;