#!/usr/bin/env perl

package srvpath::CLI;

use utf8;
use v5.44;

use lib 'lib';

use Path::Try;
use Getopt::Long
  qw(GetOptionsFromArray :config no_ignore_case bundling passthrough autoabbrev);
use Const::Fast;
use IO::Handle::Common;
use WWW::srvpath;
use WWW::srvpath::Base 'refstr';

sub configure ( $argv //= \@ARGV ) {
    my %cliopt = ();

    const my %pos_dest => ( 0 => 'root', 1 => 'mount' );

    GetOptionsFromArray(
        $argv, \%cliopt,

        # 'port:i',
        'ssl|tls|x509:s',    # = server, client, mutual (default: server)
        'certfile|certificate|ssl-cert-file|ssl-certfile:s',
        'validpath|intermediates|trustchain:s@'
        , # intermediate(s) as separate files (we may produce more specialized bundles similar to cfssl)
        'certbundle:s'
        ,    # leaf cert with intermediates/trust chain in a single file

        # 'intermediates|chain:s'
        'keyfile|key|ssl-key-file|ssl-keyfile:s',

        # Auth Basic
        'user|username:s',
        'pwhash|password-hash|crypt:s',             # argon2 hash
        'login|login-credentials|credentials:s',    # user:pwhash

        'verbose+',
        'debug', 'help',
        'version',

  # TODO: decide if its better to normalize these differnet option forms here or
  # in the WWW::srpath `ADJUST :params` block(s):
  #
  # - srvpath::CLI sub
  #   - a sub routine reference should handle it if its all done here and the
  #     paradigm is normal/familiar
  #   - no segfaults/panics (developer included)
  #
  # - WWW::srvpath
  #   - the :params attribute for ADJUST seems a perfect fit for transforming #
  #     values into what your class wants
  #   - a progmatic interface is planned so this won't be the only place these
  #     options may need to be handled in different forms
  #
  # current winnner: WWW::cgit object construction `ADJUST :params``

        'config|config-file|config-path:s@',

        'path|srvpath|root|public|www:s@',    # valid input:
            #- list of root paths, mounted as basename in value of mount

        'pathmap|rootmount|srcdest|srvpaths:s@',    # valid input:
            #- list of root paths, mounted as basename in value of mount
            # - list of colon separated root:mout pairs

        'mount|endpoint|urlbase|uribase:s',    # valid input:
            #- a single base uri path one or more local paths will be mounted in
        '<>' => sub ($barearg) {
            state $pos //= 0;
            if ( my ( $root, $mount ) = ( $barearg =~ /^([^:]+):([.+])$/ ) ) {

                if ($pos) {
                    use Data::Printer;
                    say STDERR
                      "Local root and URI mount path have already been set: ";
                    p $cliopt{root}, $cliopt{map};

                    say STDERR
"Use only the 'root:mount' format as a value for --pathmap or as positional arguments to set multiple custom mappings.";

                    return;
                }

                push $cliopt{pathmap}->@*, { root => $root, mount => $mount };
            }
            else {

                error
                  "Positional arguments for 'root' and and 'mount' have already"
                  . " been set.\n Ignoring '$barearg'."
                  if $pos > 1;

                $cliopt{ $pos_dest{$pos} } = $barearg;
                $pos++;
            }
        }
    );

    # Remove options separator (not sure the change that made this necessary...)
    shift @$argv
      if refstr($argv) eq 'ARRAY' && $$argv[0] && $$argv[0] =~ /^--?$/;

    WWW::srvpath->new(

        # Replace dashes with underscores for WWW::srvpath constructor
        map { $_ =~ s/-/_/g; ( $_ => $cliopt{$_} ) }
          keys %cliopt
    );

}

package srvpath::Runner;

use utf8;
use v5.44;

use IO::Handle::Common;

my $srvpath = srvpath::CLI::configure( \@ARGV );
my $psgi    = $srvpath->to_psgi;

unless (caller) {
    require Plack::Runner;

    my $runner = Plack::Runner->new;
    $runner->parse_options(@ARGV);

    $runner->run($psgi);

    error "$! ($?)" if $? > 0;
    exit $?;
}

return $psgi
