package Modern::OpenAPI::Generator::CLI;

use v5.26;
use strict;
use warnings;
use Carp qw(croak);
use Getopt::Long qw(GetOptionsFromArray);
use Path::Tiny qw(path);
use Modern::OpenAPI::Generator ();

# Resolves --client / --server / --ui and --no-* from raw argv (before Getopt mutates it).
#
# No such flags  -> (1,1,1) full stack.
# Only --no-*    -> start from (1,1,1), turn off each mentioned flag.
# Any --client / --server / --ui (positive) appears -> start (0,0,0), apply all flags in order
# (--client --server does NOT imply --ui; add --ui explicitly if you want Swagger UI).
sub _resolve_feature_flags {
    my ($argv) = @_;
    my @tokens = grep { /^--(no-)?(client|server|ui)$/ } @$argv;
    return ( 1, 1, 1 ) unless @tokens;

    my $has_positive = grep { /^--(client|server|ui)$/ } @tokens;

    if ( !$has_positive ) {
        my ( $c, $s, $u ) = ( 1, 1, 1 );
        for (@tokens) {
            /^--no-client$/ && do { $c = 0; next };
            /^--no-server$/ && do { $s = 0; next };
            /^--no-ui$/     && do { $u = 0; next };
        }
        return ( $c, $s, $u );
    }

    my ( $c, $s, $u ) = ( 0, 0, 0 );
    for (@tokens) {
        if    (/^--client$/)       { $c = 1 }
        elsif (/^--no-client$/)    { $c = 0 }
        elsif (/^--server$/)      { $s = 1 }
        elsif (/^--no-server$/)    { $s = 0 }
        elsif (/^--ui$/)          { $u = 1 }
        elsif (/^--no-ui$/)        { $u = 0 }
    }
    return ( $c, $s, $u );
}

sub run {
    my ( $class, @argv ) = @_;
    my @orig_argv = @argv;
    my $spec;
    my $output = '.';
    my $name;
    my ( $sync, $async ) = ( 1, 1 );
    my $skeleton   = 0;
    my $local_test = 0;
    my $force      = 0;
    my $merge      = 0;
    my @signatures;

    GetOptionsFromArray(
        \@argv,
        'spec=s'       => \$spec,
        'output|o=s'   => \$output,
        'name|n=s'     => \$name,
        'sync!'        => \$sync,
        'async!'       => \$async,
        'skeleton'     => \$skeleton,
        'local-test'   => \$local_test,
        'force'        => \$force,
        'merge'        => \$merge,
        'signature=s@' => \@signatures,
        'help|h' => \my $help,
    ) or _usage();

    _usage() if $help;

    my ( $client, $server, $ui ) = _resolve_feature_flags( \@orig_argv );

    $spec //= $argv[0];
    $output = '.' if !defined $output || !length $output;
    croak "Usage: oapi-perl-gen --name MyApp::API [--spec openapi.yaml] [--output DIR]\n" unless $spec;
    croak "--name is required (Perl package prefix)\n" unless $name;

    croak "At least one of --client, --server, or --ui must stay enabled "
      . "(use defaults or omit all --no-* flags).\n"
      if !$client && !$server && !$ui;

    if ( @signatures == 1 && $signatures[0] =~ /,/ ) {
        @signatures = split /,/, $signatures[0];
    }

    Modern::OpenAPI::Generator->new(
        spec_path      => $spec,
        output_dir     => $output,
        name           => $name,
        client         => $client,
        server         => $server,
        ui             => $ui,
        sync           => $sync,
        async          => $async,
        skeleton       => $skeleton,
        force          => $force,
        merge          => $merge,
        signatures     => \@signatures,
        local_test     => $local_test,
    )->run;

    print "Generated under $output (package $name)\n";
    return 0;
}

sub _usage {
    print <<'USAGE';
oapi-perl-gen -- OpenAPI generator (Modern::OpenAPI::Generator)

  --name, -n       Root Perl package (required), e.g. MyApp::API
  --spec FILE      OpenAPI 3.x YAML/JSON (positional arg also accepted)
  --output, -o     Output directory (default: .)

  Feature selection (client / server / Swagger UI):

    If you pass none of: --client, --no-client, --server, --no-server, --ui, --no-ui,
    all three are generated (default "full" mode).

    If you pass only --no-* flags, each turns that feature off; the rest stay on
    (example: --no-ui => client + server, no embedded Swagger UI).

    If you pass at least one of --client, --server, or --ui (positive), only the
    features you set explicitly are generated (--client --server does not add UI).

    Examples:
      --client                         => client only
      --client --server                => client + server, no UI
      --client --server --ui           => client + server + Swagger UI
      --client --server --no-ui        => client + server, no UI
      --no-ui                          => client + server, no UI
      --no-server --no-ui              => client only

  Swagger UI: when server and UI are generated, GET /openapi.yaml prepends the
  current request origin (scheme/host/port from your daemon -l URL) to `servers`
  so "Try it out" targets the running app.

  --sync / --no-sync       Emit Client::Sync (default: on)
  --async / --no-async     Emit Client::Async (default: on)

  --skeleton               Server controller stubs without TODO comments

  --local-test             With --server: controllers use ::StubData + ::Model::* (random
                           payload, from_json) instead of 501. Also emits ::Model::* when
                           --no-client (models are required for local stubs).

  --signature hmac         Emit Auth::Plugin::Hmac (repeat or comma-separated)
  --signature bearer       Emit Auth::Plugin::Bearer

  --force                  Overwrite existing files
  --merge                  Skip files that already exist

  --help, -h

USAGE
    exit 0;
}

1;

__END__

=encoding utf8

=head1 NAME

Modern::OpenAPI::Generator::CLI - Command-line driver for L<Modern::OpenAPI::Generator>

=head1 SYNOPSIS

  oapi-perl-gen --name MyApp::API --output ./out openapi.yaml
  oapi-perl-gen --help

=head1 DESCRIPTION

Parses arguments (see C<run> in this package) and invokes
C<< Modern::OpenAPI::Generator->new(...)->run >>. Feature selection for
C<--client>, C<--server>, and C<--ui> follows the rules documented in the
C<_resolve_feature_flags> helper and in C<oapi-perl-gen --help>.

=head2 run

Parses C<@ARGV>, constructs L<Modern::OpenAPI::Generator> with the selected
options, calls C<< ->run >>, prints a one-line summary, and returns exit status
C<0>.

=head1 SEE ALSO

L<Modern::OpenAPI::Generator>, the C<oapi-perl-gen> script.

=cut
