package Galileo::Command::setup;
use Mojo::Base 'Mojolicious::Command';

use Mojolicious::Command::daemon;

use Mojolicious::Routes;
use Mojo::JSON 'j';
use Mojo::Util 'spurt';

use Galileo::DB::Deploy;

has description => "Configure your Galileo CMS via a web interface\n";

sub run {
  my ($self, @args) = @_;

  my $app = $self->app;

  my $r = Mojolicious::Routes->new;
  $app->routes($r); # remove all routes

  push @{ $app->renderer->classes }, __PACKAGE__;

  $app->helper( dh => sub {
    my $self = shift;
    state $dh = Galileo::DB::Deploy->new( schema => $self->app->schema );
    $dh;
  });

  $app->helper( 'control_group' => sub {
    my $self = shift;
    my $contents = pop;
    my %args = @_;
 
    $self->render(
      partial => 1,
      template => 'control_group',
      'control_group.contents' => ref $contents ? $contents->() : $contents,
      'control_group.label' => $args{label} || '',
      'control_group.for'   => $args{for}   || '',
    );
  });

  $r->any( '/' => 'galileo_setup' );
  $r->any( '/configure' => 'galileo_config' );
  $r->any( '/store_config' => sub {
    my $self = shift;
    my @params = sort $self->param;

    # map JSON keys to Perl data
    my %params = map { $_ => scalar $self->param($_) } @params;
    foreach my $key ( qw/extra_css extra_js extra_static_paths secrets db_options/ ) {
      $params{$key} = j($params{$key});
    }

    spurt $self->dumper(\%params), $self->app->config_file;
  
    $self->app->load_config;
    $self->humane_flash( 'Configuration saved' );
    $self->redirect_to('/');
  });

  $r->any( '/database' => sub {
    my $self = shift;

    my $dh = $self->dh;
    my $schema = $dh->schema;

    my $available = $schema->schema_version;

    # Nothing installed
    unless ( $dh->has_admin_user ) {
      return $self->render( 'galileo_database_install' );
    }

    # Something is installed, check for a version
    my $installed = $dh->installed_version || $dh->setup_unversioned;

    # Do nothing if version is current
    if ( $installed == $available ) {
      $self->flash( 'galileo.message' => 'Database schema is current' );
    } else {
      $self->flash( 'galileo.message' => "Upgrade database $installed -> $available" );
      $dh->do_upgrade;
    }

    $self->redirect_to('finish');
  });

  $r->any( '/database_install' => sub {
    my $self = shift;
    my $pw1 = $self->param('pw1');
    my $pw2 = $self->param('pw2');
    unless ( $pw1 eq $pw2 ) {
      $self->humane_flash( q{Passwords don't match!} );
      return $self->redirect_to('database');
    }

    my $dh = $self->dh;
    my $user = $self->param('user');
    my $full = $self->param('full');

    eval { $dh->schema->deploy };
    eval { $dh->do_install };
    eval { $dh->inject_sample_data($user, $pw1, $full) };
    if ($@) {
      my $error = "$@";
      chomp $error;
      $self->humane_flash( $error );
      return $self->redirect_to('database');
    }

    $self->flash( 'galileo.message' => 'Database has been setup' );
    $self->redirect_to('finish');
  });

  $r->any('/finish' => sub {
    my $self = shift;
    my $message = $self->flash( 'galileo.message' );

    # check that an admin user exists
    if ( $self->app->dh->has_admin_user ) {
      $self->stash( 'galileo.success' => 1 );
      $self->stash( 'galileo.message' => $message );
    } else {
      $self->stash( 'galileo.success' => 0 );
      $self->stash( 
        'galileo.message' =>
        'It does not appear that your database is setup, please rerun the setup utility'
      );
    }

    $self->humane_stash( 'Goodbye' );
    $self->render('galileo_finish');
  });

  $r->any('/exit' => sub { exit });

  $self->Mojolicious::Command::daemon::run(@args);
}

1;


__DATA__

@@ galileo_setup.html.ep

% title 'Galileo Setup - Home';
% layout 'basic';

<p>Welcome to Galileo! This utility helps you setup your Galileo CMS.</p>

<ul>
  %= tag li => begin 
    %= link_to 'Configure your Galileo CMS' => 'configure'
    <p>Configuration is not necessary, defaults can be used. 
    Configuring Galileo CMS should be done before installing the database.</p>
  % end

  %= tag li => begin
    %= link_to 'Install or upgrade your database' => 'database'
    <p>If this is a new installation you <b>must</b> to run the database setup utility.
    If you have not configured Galileo (see above), you will use the defaults, including using an SQLite database for the backend.</p>
  % end

  %= tag li => begin
    %= link_to 'Stop and exit' => 'finish'
    <p>If your database is already installed, you may stop this utility and run <pre>$ galileo daemon</pre></p>
  % end

</ul>

@@ galileo_config.html.ep

% use Mojo::JSON 'j';
% title 'Galileo Setup - Configure';
% layout 'basic';

%= form_for 'store_config' => method => 'POST', class => 'form-horizontal' => begin
  % my $config = app->config;

  <legend>Database Connection</legend>
  %= control_group for => 'db_dsn', label => 'Connection String (DSN)' => begin
    %= text_field 'db_dsn', value => $config->{db_dsn}, class => 'input-block-level'
  % end
  %= control_group for => 'db_username', label => 'Username' => begin
    %= text_field 'db_username', value => $config->{db_username}, class => 'input-block-level'
  % end
  %= control_group for => 'db_password', label => 'Password' => begin
    %= input_tag 'db_password', value => $config->{db_password}, type => 'password', class => 'input-block-level'
  % end
  %= control_group for => 'db_options', label => 'Options (JSON hash)' => begin
    %= text_field 'db_options', value => j($config->{db_options}), class => 'input-block-level'
  % end
  %= control_group for => 'db_schema', label => 'Schema Class' => begin
    %= text_field 'db_schema', value => $config->{db_schema}, class => 'input-block-level'
  % end

  <legend>Additional Files</legend>

  %= control_group for => 'files', label => 'Extra Static Paths (JSON array)' => begin
    %= text_field 'extra_static_paths', value => j($config->{extra_static_paths}), class => 'input-block-level'
  % end
  %= control_group for => 'extra_js', label => 'Extra Javascript Files (JSON array)' => begin
    %= text_field 'extra_js', value => j($config->{extra_js}), class => 'input-block-level'
  % end
  %= control_group for => 'extra_css', label => 'Extra Stylesheet files (JSON array)' => begin
    %= text_field 'extra_css', value => j($config->{extra_css}), class => 'input-block-level'
  % end
  %= control_group for => 'upload_path', label => 'Upload Path' => begin
    %= text_field 'upload_path', value => $config->{upload_path}, class => 'input-block-level'
  % end

  <legend>Other Options</legend>

  %= control_group for => 'sanitize', label => 'Use Sanitizing Editor' => begin 
    % if($config->{sanitize}){
      %= check_box 'sanitize', value => 1, checked => 'checked'
    % } else {
      %= check_box 'sanitize', value => 1
    % }
    %= hidden_field 'sanitize' => 0
  % end
  %= control_group for => 'secrets', label => 'Application Secrets (JSON array)' => begin
    %= text_field 'secrets', value => j($config->{secrets}), class => 'input-block-level'
  % end
  %= control_group for => 'submit-button', begin
    <button class="btn" id="submit-button" type="submit">Save</button>
    %= link_to 'Cancel' => '/' => class => 'btn'
  % end
% end

@@ galileo_database_install.html.ep

% title 'Galileo Setup - Database';
% layout 'basic';

%= form_for 'database_install' => method => 'POST', class => 'form-horizontal' => begin
  %= control_group for => 'full', label => 'Admin Full Name' => begin
    %= text_field 'full', class => 'input-block-level'
  % end
  %= control_group for => 'user', label => 'Admin Username' => begin
    %= text_field 'user', class => 'input-block-level'
  % end
  %= control_group for => 'pw1', label => 'Password' => begin
    %= input_tag 'pw1', type => 'password', class => 'input-block-level'
  % end
  %= control_group for => 'pw2', label => 'Repeat Password' => begin
    %= input_tag 'pw2', type => 'password', class => 'input-block-level'
  % end

  %= control_group for => 'submit-button', begin
    <button class="btn" id="submit-button" type="submit">Save</button>
    %= link_to 'Cancel' => 'finish' => class => 'btn'
  % end
% end

@@ galileo_finish.html.ep

% title 'Galileo Setup - Finished';
% layout 'basic';

% if ( my $message = stash 'galileo.message' ) {
  <p><%= $message %></p>
% }

% if ( stash 'galileo.success' ) {
  <p>Setup complete, run <pre>$ galileo daemon</pre></p>
% }

%= javascript begin
  $(function(){ $.get('<%= url_for 'exit' %>') });
% end

@@ control_group.html.ep

<div class="control-group">
  % if (my $label = stash 'control_group.label') {
    % my @for;
    % if ( my $for = stash 'control_group.for' ) {
      % push @for, for => $for;
    % }
    %= tag label => class => 'control-label', @for, begin
      %= $label 
    % end
  % }
 
  <div class="controls">
    %= stash 'control_group.contents'
  </div>
</div>