#!/usr/bin/env perl

use v5.10;
use Cwd;
use File::Copy;
use File::Copy::Recursive 'dircopy';
use Dancer2::Core::Runner;
use Dancer2::Core::App;
use Strehler;
use Strehler::Schema;
use Term::ReadKey;
use Authen::Passphrase::BlowfishCrypt;

my $strehler_root = $INC{'Strehler.pm'};
$strehler_root =~ s/\.pm$//;
my %available_commands = ('commands' => 'show available commands',
                          'statics' => 'copy of static resources needed by Strehler to Dancer2 App',
                          'demo' => 'create a complete Dancer2 App with Strehler already configured, for trial purpose',
                          'initdb' => 'generate strehler tables on the wanted database',
                          'layout' => 'import Strehler Admin layout, mandatory for admin interface extension',
                      );

my $command = shift;
my @parameters = @ARGV;

print "\n### Strehler CMS Manager ###\n\n";
print "Strehler Version: " . $Strehler::VERSION . "\n\n";

if($command eq 'statics')
{
    statics(@parameters);
}
elsif($command eq 'initdb')
{
    initdb(@parameters);
}
elsif($command eq 'layout')
{

    layout(@parameters);
}
elsif($command eq 'demo')
{
    print "-demo- command: $available_commands{'demo'}\n\n";
    my $app  = shift @parameters || 'StrehlerDemo';
    say "STEP 1: Creating Dancer App... $app";
    system("dancer2 -a $app");
    print "\n\n";
    chdir $app;
    demo_components();
    statics();
    initdb(undef, 1);
    layout();
    say "Demo SUCCESSFULLY DEPLOYED!";
    say "Run Dancer2 devserver under $app, go to ADDRESS:PORT/admin, insert admin as user and as password and ENJOY!\n\n";
}
else
{
    if($command eq 'commands')
    {
        print "-commands- command: $available_commands{'commands'}\n\n";
    }
    else
    {
        print "Wrong command provided. I'll show you available commands\n\n";
    }
    for(keys %available_commands)
    {
        say $_ . " => " . $available_commands{$_};
    }
    print "\n\n";
}

sub statics
{
    my $public_dir = shift || 'public';

    print "-statics- command: $available_commands{'statics'}\n\n";

    my $origin = $strehler_root . '/public';

    my $app_directory = getcwd();
    my $destination = $app_directory . '/' . $public_dir;

    if(! -d $destination)
    {
        say "Directory $destination doesn't exists!";
        if($public_dir eq 'public')
        {
            print "\"public\" directory used as standard dancer static files directory. Different from yours? Pass your directory as second parameter to the script\n";
        }
        print "\n\n";
        exit();
    }

    say "Copying statics from $origin to $destination...";
    dircopy($origin, $destination);
    mkdir $destination . '/upload';
    say "Creating upload directory...";
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    else
    {
        print "\nSUCCESS! Files copied in your Dancer2 App!\n\n";
    }
    mkdir 'public/upload';
}

sub initdb
{
    my $wanted_schema = shift; 
    my $demo = shift || 0;

    print "-initdb- command: $available_commands{'initdb'}\n\n";

    my $dsn;
    my $user;
    my $password;

    if(! $demo)
    {
        my $runner = Dancer2::Core::Runner->new( caller => getcwd() . "/bin" );
        my $app = Dancer2::Core::App->new(
            name            => "dummy",
            environment     => $runner->environment,
            location        => $runner->location,
            runner_config   => $runner->config,
            postponed_hooks => $runner->postponed_hooks,
        );
  
        if(! $app->config->{'plugins'}->{'DBIC'})
        {
            say "Can't read config.yml or no DBIC plugin configured in it\n";
            exit();
        }
        my $schema_name = $wanted_schema || 'default';
        if(! $app->config->{'plugins'}->{'DBIC'}->{$schema_name} && $wanted_schema)
        {
            say "Schema $wanted_schema doesn't exists in the config.yml file we're using!\n";
            exit();
        }
        if(! $wanted_schema && ! $app->config->{'plugins'}->{'DBIC'}->{'default'})
        {
            my @availables = keys %{$app->config->{'plugins'}->{'DBIC'}};
            $schema_name = $availables[0];
        }
        $dsn = $app->config->{'plugins'}->{'DBIC'}->{$schema_name}->{'dsn'};
        $user = $app->config->{'plugins'}->{'DBIC'}->{$schema_name}->{'user'};
        $password = $app->config->{'plugins'}->{'DBIC'}->{$schema_name}->{'pass'};
        print "Schema: $schema_name\n\n";
        say "DSN: $dsn";
        say "User: $user";
        say "Password: $password";
        my $continue = "";
        while($continue ne 'Y' && $continue ne 'N')
        {
            ReadMode(1, *STDIN);
            say "\nWARNING: this script will ERASE (DROP TABLE) all the tables with a name used by Strehler tables. Are you sure you want to continue? (y/n)";
            $continue = <STDIN>;
            ReadMode(0);
            chomp $continue;
            $continue = uc($continue);
        }
        if($continue eq 'N')
        {
            print "NO DEPLOY. Exiting...\n\n";
            exit();
        }
    }
    else
    {
        $dsn = "dbi:SQLite:dbname=demo.sqlite";
        $user = undef;
        $password = undef;
    }
    my $schema = Strehler::Schema->connect($dsn, $user, $password);
    $schema->deploy( { add_drop_table => 1 } );
    my $user_password;
    if(! $demo)
    {
        ReadMode(2, *STDIN);
        say "Enter password for admin:";
        $user_password = <STDIN>;
        say "Re-type password:";
        my $user_password_confirm = <STDIN>;
        ReadMode(0);
        if(! ($user_password eq $user_password_confirm))
        {
            say "Password inputs don't match!";
            exit(0);
        }
        chomp $user_password;
    }
    else
    {
        $user_password = 'admin';
    }
    my $ppr = Authen::Passphrase::BlowfishCrypt->new(
                    cost => 8, salt_random => 1,
                    passphrase => $user_password);
    my $hash = $ppr->hash_base64;
    my $salt = $ppr->salt_base64;
    $schema->populate('User', [[qw/user password_hash password_salt role/],
                              ['admin', $hash, $salt, 'admin']]);

    print "Database deploy COMPLETED!\n\n";
}

sub layout
{
    my $views_dir  = shift  || 'views';
    print "-layout- command: $available_commands{'layout'}\n\n";
    my $origin = $strehler_root . '/views/layouts/admin.tt';

    my $app_directory = getcwd();
    my $destination = $app_directory . '/' . $views_dir . '/layouts';

    if(! -d $destination)
    {
        say "Directory $destination doesn't exists!";
        if($views_dir eq 'views')
        {
            print "\"views\" directory used as standard dancer views files directory. Different from yours? Pass your directory as second parameter to the script\n";
        }
        print "\n\n";
        exit();
    }

    say "Copying layout from $origin to $destination...";
    copy($origin, $destination . '/admin.tt');
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    else
    {
        print "\nSUCCESS! Files copied in your Dancer2 App!\n\n";
    }
}

sub demo_components
{
    my $origin = $strehler_root . '/demo';
    my $app_directory = getcwd();
    my $destination = $app_directory;
    say "Demo resources will be injected in the app...";
    say "$origin -> $destination";
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    say "Config.yml...";
    copy($origin . "/config.yml", $destination . '/config.yml');
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    say "Demo.pm...";
    copy($origin . "/Demo.pm.ex", $destination . '/lib/Demo.pm');
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    say "app.pl...";
    copy($origin . "/app.pl", $destination . '/bin/app.pl');
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
    say "strehler-home.tt...";
    copy($origin . "/strehler-home.tt", $destination . '/views/strehler-home.tt');
    if($!)
    {
        print "\nCOPY FAILED! A problem occured: $!\n\n";
    }
}
