#!/usr/bin/env perl
use v5.40;

use Getopt::Long qw/ :config bundling pass_through /;
use Pod::Usage;

use IO::Socket::INET;
use Minima;
use Minima::Project;

my $help;
my $version;
my $command;

GetOptions(
    'h|help!' => \$help,
    'v|version!' => \$version,
);
# From here on, commands must give the final word on passed options
Getopt::Long::Configure('no_pass_through');

# Preliminary
pod2usage(-exitval => 0, -verbose => 2) if $help;
say 'Minima ', Minima->VERSION and exit if $version;

# Commands
$command = shift @ARGV // 'nop';

if ($command eq 'new') {
    my %config;
    GetOptions(
        \%config,
        'cpanfile!',
        'static|s!',
        'verbose!',
    );
    Minima::Project::create(shift @ARGV, \%config);
} elsif ($command eq 'run') {
    # Attempt to find a free port
    my $port = 5000;
    while (++$port < 2**16) {
        my $sock = IO::Socket::INET->new(
            PeerAddr => '127.0.0.1',
            PeerPort => $port,
            Proto => 'tcp',
            Timeout => 5,
        );
        last unless defined $sock;
    }

    my @plackup = qw(
        plackup
        app.psgi
        --reload
        --access-log /dev/null
        --host localhost
        --port
    );
    push @plackup, $port;
    push @plackup, @ARGV;

    exec @plackup;
    die "Failed to execute plackup.\n";
} else {
    # No valid command passed
    pod2usage(
        -verbose => 99,
        -sections => 'SYNOPSIS|GLOBAL OPTIONS',
    );
}

__END__

=head1 NAME

minima -- Manage web applications using Minima.

=head1 SYNOPSIS

    minima [command] [-hv] [args..]

    minima new [options] [name]

=head1 DESCRIPTION

The B<minima> script provides a command-line interface to manage
projects built with the L<Minima> web framework.

=head1 GLOBAL OPTIONS

=over 4

=item B<-h>, B<--help>

Show the manual page.

=item B<-v>, B<--version>

Show version information.

=back

=head1 COMMANDS

=head2 new I<name> [options]

Create a new project using the standard Minima template.

If F<name> is provided, a new directory with the given name will be
created. If no F<name> is provided, the project will be created in the
current directory. The specified directory must be empty.

=head3 Options

All options can be inverted by using the C<no-> prefix.

=over 4

=item B<--cpanfile> I<(default: false)>

Generate a F<cpanfile> in the new project root. This file declares the
basic dependencies required by the generated application, allowing you
to install them with L<Carton> or similar tools. By default, no
F<cpanfile> is created unless this option is specified.

=item B<--static, -s> I<(default: true)>

Enables the middleware to serve static files from the F<static/>
directory during development.

=item B<--verbose> I<(default: false)>

Outputs directories and files as they are created.

=back

=head2 run [options]

Runs the current F<app.psgi> by automatically detecting the next
available port after 5000 and forwarding the command to L<plackup>.
Equivalent to:

    plackup                    \
        --reload               \
        --access-log /dev/null \
        --host localhost       \
        --port <port>          \
        app.psgi

Any options passed to B<run> are forwarded directly to plackup.

=head1 SEE ALSO

L<Minima> -- The web framework used by B<minima>.

=head1 AUTHOR

Cesar Tessarin, <cesar@tessarin.com.br>.

Written in September 2024.
