#!/usr/bin/env perl
use warnings;
use strict;
use EV ();
use Feersum ();

require Getopt::Long;

my $native = 0;
Getopt::Long::Configure("no_ignore_case", "no_auto_abbrev", "pass_through");
Getopt::Long::GetOptions(
    "native!" => \$native,
);

my $runner;

if ($native) {
    my $listen = 'localhost:5000';
    my $pre_fork = 0;
    my $verbose = 0;
    my $reuseport = 0;
    my $epoll_exclusive = 0;
    my ($read_priority, $write_priority, $accept_priority);
    my ($keepalive, $read_timeout, $max_connection_reqs, $max_accept_per_loop, $max_connections);
    Getopt::Long::GetOptions(
        "listen=s" => \$listen,
        "pre-fork=i" => \$pre_fork,
        "verbose!" => \$verbose,
        "reuseport!" => \$reuseport,
        "epoll-exclusive!" => \$epoll_exclusive,
        "read-priority=i" => \$read_priority,
        "write-priority=i" => \$write_priority,
        "accept-priority=i" => \$accept_priority,
        "keepalive!" => \$keepalive,
        "read-timeout=i" => \$read_timeout,
        "max-connection-reqs=i" => \$max_connection_reqs,
        "max-accept-per-loop=i" => \$max_accept_per_loop,
        "max-connections=i" => \$max_connections,
    );
    # Validate priority values (-2 to +2 per libev)
    for my $prio ([$read_priority, 'read'], [$write_priority, 'write'], [$accept_priority, 'accept']) {
        if (defined $prio->[0] && ($prio->[0] < -2 || $prio->[0] > 2)) {
            die "Error: --$prio->[1]-priority must be between -2 and 2\n";
        }
    }
    require Feersum::Runner;
    my $app_file = pop @ARGV || 'app.feersum';
    $runner = Feersum::Runner->new(
        'listen' => [$listen],
        app_file => $app_file,
        pre_fork => $pre_fork,
        quiet => !$verbose,
        reuseport => $reuseport,
        epoll_exclusive => $epoll_exclusive,
        (defined $read_priority ? (read_priority => $read_priority) : ()),
        (defined $write_priority ? (write_priority => $write_priority) : ()),
        (defined $accept_priority ? (accept_priority => $accept_priority) : ()),
        (defined $keepalive ? (keepalive => $keepalive) : ()),
        (defined $read_timeout ? (read_timeout => $read_timeout) : ()),
        (defined $max_connection_reqs ? (max_connection_reqs => $max_connection_reqs) : ()),
        (defined $max_accept_per_loop ? (max_accept_per_loop => $max_accept_per_loop) : ()),
        (defined $max_connections ? (max_connections => $max_connections) : ()),
    );
}
else {
    my @args = (
        server => 'Feersum',
        env => 'deployment',
        version_cb => sub {
            print "Feersum $Feersum::VERSION on EV $EV::VERSION\n";
        }
    );
    require Plack::Runner;
    $runner = Plack::Runner->new(@args);
    $runner->parse_options(@ARGV);
}

$runner->run;

__END__

=head1 NAME

feersum - feersum app loader

=head1 SYNOPSIS

  feersum [plackup opts] [--pre-fork=N] [app.psgi]
  feersum --native [--listen host:port] [--pre-fork=N] [app.feersum]

=head1 DESCRIPTION

Loads the specified app file into a Feersum server.

In both cases, if C<--pre-fork=N> is specified, that many worker processes are
used to serve requests. See L<Feersum::Runner> for details.

If in native mode (when running C<feersum --native>), the following options
are available:

=over 4

=item C<--listen host:port>

Address to listen on. Default is localhost:5000. IPv6 addresses should use
bracket notation: C<--listen [::1]:5000>

=item C<--pre-fork=N>

Fork N worker processes to handle requests.

=item C<--verbose>

Enable verbose output.

=item C<--reuseport>

Enable SO_REUSEPORT for better load distribution across workers.

=item C<--epoll-exclusive>

Enable EPOLLEXCLUSIVE mode (Linux 4.5+) for exclusive wakeup of workers.

=item C<--read-priority=N>

Set EV priority for read events (-2 to 2).

=item C<--write-priority=N>

Set EV priority for write events (-2 to 2).

=item C<--accept-priority=N>

Set EV priority for accept events (-2 to 2).

=item C<--keepalive> / C<--no-keepalive>

Enable or disable HTTP keep-alive connections.

=item C<--read-timeout=N>

Set read/keep-alive timeout in seconds.

=item C<--max-connection-reqs=N>

Maximum requests per keep-alive connection (0 for unlimited).

=item C<--max-accept-per-loop=N>

Maximum connections to accept per event loop iteration (default: 64).

=item C<--max-connections=N>

Maximum concurrent connections (0 for unlimited). Provides DoS protection.

=back

When running in PSGI mode (non-native), L<Plack::Runner> is used.  See that
module for documentation and defaults.

=cut
