# PSGI app that can replace FastCGI server
#
# To use it with uWSGI, use for example:
#
# $ uwsgi --plugins psgi --socket :5000 --psgi e2e-tests/llng-server.psgi
#
# Set LLNG_DEFAULTCONFFILE if it is not in the right place
#$ENV{LLNG_DEFAULTCONFFILE} = 'e2e-tests/conf/lemonldap-ng.ini';

our (
  $sourceServer
);

$sourceServer ||= $ENV{SOURCE_SERVER} || 'nginx';
my $class = (
      $sourceServer eq 'nginx'   ? 'Lemonldap::NG::Handler::Server::Nginx'
    : $sourceServer eq 'traefik' ? 'Lemonldap::NG::Handler::Server::Traefik'
    :                              die("Unknown server $sourceServer")
);

my %builder = (
    handler => sub {
        eval "require $class";
        return $class->run( {} );
    },
    reload => sub {
        eval "require $class";
        return $class->reload();
    },
    manager => sub {
        require Lemonldap::NG::Manager;
        return Lemonldap::NG::Manager->run( {} );
    },
    portal => sub {
        require Lemonldap::NG::Portal;
        return Lemonldap::NG::Portal->run( {} );
    },
    cgi => sub {
        require CGI::Emulate::PSGI;
        require CGI::Compile;
        return sub {
            my $script = $_[0]->{SCRIPT_FILENAME};
            return $_apps{$script}->(@_) if ( $_apps{$script} );
            $_apps{$script} =
              CGI::Emulate::PSGI->handler( CGI::Compile->compile($script) );
            return $_apps{$script}->(@_);
        };
    },
    psgi => sub {
        return sub {

            # Fix PATH_INFO when using Nginx with default uwsgi_params
            # See #2031
            ( $_[0]->{PATH_INFO} ) =
              $_[0]->{REQUEST_URI} =~ /^(?:\Q$_[0]->{SCRIPT_NAME}\E)?([^?]*)/;

            my $script = $_[0]->{SCRIPT_FILENAME};
            return $_apps{$script}->(@_) if ( $_apps{$script} );
            $_apps{$script} = do $script;
            unless ( $_apps{$script} and ref $_apps{$script} ) {
                my $errmsg = $@ || $! || "unknown error";
                die("Unable to load $_[0]->{SCRIPT_FILENAME}: $errmsg");
            }
            return $_apps{$script}->(@_);
        }
    },
);

# This middleware is a workaround for the fact that UWSGI does not
# automatically downgrade UTF8 strings, unlike Apache and FastCGI
# We can't blame it because PSGI responses are supposed to be byte string, not
# unicode strings
# It can be disabled by setting the LLNG_SKIPUTF8DOWNGRADE environment variable
sub optional_utf8_middleware {
    my $app = shift;
    if ( !$ENV{LLNG_SKIPUTF8DOWNGRADE} ) {
        return sub {
            my $env = shift;
            my $res = $app->($env);

            # Downgrade headers
            map { utf8::downgrade($_) } @{ $res->[1] };

            # Downgrade body
            map { utf8::downgrade($_) } @{ $res->[2] }
              if ref( $res->[2] ) eq "ARRAY";
            return $res;
        };
    }
    else {
        return $app;
    }
}

sub {
    my $type = $_[0]->{LLTYPE} || 'handler';
    return $_apps{$type}->(@_) if ( defined $_apps{$type} );
    if ( defined $builder{$type} ) {
        my $app = $builder{$type}->();
        $_apps{$type} = optional_utf8_middleware($app);
        return $_apps{$type}->(@_);
    }
    die "Unknown PSGI type $type";
};
