#!/usr/bin/env perl
# Hidden actions:
# Install dependencies:
# $ script/convos install
# Same as above, but also install dependencies required for development
# $ script/convos install develop

BEGIN {
  if ($ENV{SNAP} and $ENV{SNAP_USER_COMMON}) {
    $ENV{CONVOS_HOME} ||= $ENV{SNAP_USER_COMMON};
    @INC = map {
      my $local = "$ENV{SNAP}$_";    # Example: /snap/convos/x45/usr/share/perl5
      warn "INC: $local / $_\n" if $ENV{CONVOS_SNAP_DEBUG};
      -e $local ? $local : $_;
    } @INC;
  }
}

use strict;
use Config;
my %seen;

if ($ARGV[0] and -r $ARGV[0] and -f $ARGV[0]) {
  $ENV{MOJO_CONFIG} = shift @ARGV;
  unshift @ARGV, 'daemon' unless $ARGV[0] and $ARGV[0] eq 'daemon';
}

my $command = $ARGV[0] || '';
$ENV{MOJO_LOG_LEVEL} ||= 'fatal' if grep { $command eq $_ } qw(get version);
$ENV{MOJO_MODE} ||= 'production' if $command eq 'daemon';
$ENV{CONVOS_COMMAND_LINE} //= 1 if $command eq 'get';

unless ($ENV{CONVOS_SETUP}++) {
  eval "require $_;1" or die $@ for qw(FindBin File::Spec);
  my $bin = File::Spec->catdir($FindBin::Bin, File::Spec->updir, 'local', 'bin');
  my $cpanfile = File::Spec->catfile($FindBin::Bin, File::Spec->updir, 'cpanfile');
  my $local_lib = File::Spec->catdir($FindBin::Bin, File::Spec->updir, 'local');

  # Extra helper programs
  $ENV{PATH} = join ':', grep {$_} $bin, $ENV{PATH} if -d $bin;

  # Where cpanm might have installed dependencies to
  unshift @INC,
    grep {-d}
    map { File::Spec->catdir($FindBin::Bin, File::Spec->updir, qw(local lib perl5), @$_) }
    [$Config{version}, $Config{archname}], [$Config{version}], [$Config{archname}], [];

  # Where Convos lives
  unshift @INC, File::Spec->catdir($FindBin::Bin, File::Spec->updir, 'lib');

  # Force PERL5LIB to be loaded before the custom @INC directories above
  unshift @INC, split /:/, $ENV{PERL5LIB} if $ENV{PERL5LIB};

  # Make sure the dependencies from cpanfile is installed
  exit ensure_dependencies($cpanfile, @ARGV) if $command eq 'install';

  # Note that "morbo script/convos" will not run ensure_dependencies()
  ensure_dependencies($cpanfile, @ARGV) if __PACKAGE__ eq 'main' and -e $cpanfile;
}

@INC = grep { !$seen{$_}++ } @INC;    # duplicates are caused by "dev" command
pop @INC if @INC[-1] eq '.';          # don't care about current dir

if ($command eq 'dev') {
  $ENV{$_} = 1 for qw(MOJO_ASSETPACK_LAZY MOJO_IRC_DEBUG CONVOS_DEBUG);
  $ENV{PERL5LIB} = join ':', @INC;
  shift @ARGV;
  warn "\$ morbo script/convos @ARGV\n";
  exec qw(morbo script/convos), @ARGV;
  die "Could not exec morbo @ARGV: $!\n";
}

# Start Convos
require Mojolicious::Commands;

if ($command eq 'version') {
  open my $STDOUT, '>', \(my $stdout = '');
  select $STDOUT;
  Mojolicious::Commands->start_app('Convos');
  $stdout =~ s!CORE\s*!CORE\n  Convos      ($Convos::VERSION)\n  !s;
  print STDOUT $stdout;
}
else {
  Mojolicious::Commands->start_app('Convos');
}

sub ensure_dependencies {
  return if $ENV{CONVOS_SKIP_DEPENDENCIES_CHECK};
  my ($cpanfile, $action, $mode) = @_;
  my @cpanm = ($^X, File::Spec->catfile($FindBin::Bin, 'cpanm'));
  my $local_lib = File::Spec->catdir($FindBin::Bin, File::Spec->updir, 'local');
  my ($n, @missing) = (0);

  our $cpanfile_mode = 'default';
  local *main::on = sub { local $cpanfile_mode = shift; shift->() };
  local *main::test_requires = sub { };
  local *main::requires = sub {
    my ($module, $version) = @_;
    return if ++$n and eval "use $module $version;1";
    my $e = do {
      local $_ = $@;
      s! at .*!!s;
      s! in \@INC.*!!s;
      s!$module.*--.*?([\d\._]+).*!You have version $1!;
      $_;
    };
    push @missing, [$module, $version, $e, $cpanfile_mode];
  };

  if ($action eq 'install' and $mode and $mode ne '--develop') {
    die "Usage: $0 install [--develop]\n" if $mode and $mode ne '--develop';
  }
  if (!-r $cpanm[1]) {
    main::requires('App::cpanminus', '1.7016');    # cpanm -M ... is required
    @cpanm = qw(cpanm);
  }

  do $cpanfile;
  die "Could not source $cpanfile: $@" unless $n;
  @missing = grep { $_->[3] ne 'develop' } @missing if $mode ne '--develop';
  pop @$_ for @missing;

  if (@missing and $action ne 'install') {
    my @msg;
    push @msg, "Perl executable:", "  $^X\n", "Perl \@INC:", map({"-  $_"} @INC)
      if $ENV{CONVOS_DEBUG};
    push @msg, "\nIs is not possible to start Convos at this point, since",
      "there are some missing dependencies that need to be installed:\n",
      map({ sprintf "-  %s %s # %s", @$_ } @missing),
      qq(\nRun "$0 install" to install the missing dependencies above,),
      qq(or run "CONVOS_DEBUG=1 $0 @ARGV" for more information.\n\n);
    die join "", map {"\n$_"} @msg;
  }

  for my $m (@missing) {
    $ENV{CPAN_MIRROR} //= 'https://cpan.metacpan.org' if eval 'require IO::Socket::SSL;1';
    my @cmd = (@cpanm, '-n', -l => $local_lib);
    push @cmd, -M => $ENV{CPAN_MIRROR} if $ENV{CPAN_MIRROR};
    push @cmd, $m->[0];
    warn sprintf ">>> %s\n", join ' ', @cmd;
    system @cmd;
    die "cpanm failed!\n" if $?;
  }

  if ($action eq 'install') {
    warn join "\n", "\n-------------------------------", "All dependencies are installed!",
      qq(\nYou can now run "$0 daemon --listen http://*:8000" to start Convos.\n\n);
  }

  return 0;
}
