#!/usr/local/cpanel/3rdparty/bin/perl

#                                      Copyright 2026 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package scripts::wp2_nova_util;

use cPstrict;

=encoding utf-8

=head1 NAME

wp2_nova_util - Command-line interface for the Nova WP partner integration API

=head1 USAGE

wp2_nova_util --base-url <url> --partner-id <id> --user-id <id> [--create-user|--create-magic-link|--create-magic-link-for-user|--send-webhook-event|--send-webhook-event-for-user] [options]

=over

=item --base-url <url>

REQUIRED. The Nova WP server URL (e.g. C<https://nova-wp.webpros.dev>).

=item --partner-id <id>

REQUIRED. The partner identifier.

=item --user-id <id>

REQUIRED. The unique user identifier.

=item --timeout <seconds>

OPTIONAL. Per-request HTTP timeout, forwarded to
L<Cpanel::HTTP::Client>. When omitted, the underlying default applies.

=item --create-user

Create or retrieve a partner user. Returns the API key for the user.

Optional options: C<--user-name>, C<--user-email>, C<--locale>.

=item --create-magic-link

Generate a one-time magic link. Requires C<--api-key>.

Required options: C<--api-key>, C<--api-token>, C<--api-token-expires-at>,
C<--partner-api-url>, C<--target-domain>.

Optional options: C<--user-tracking-id>, C<--locale>, C<--return-url>.

=item --create-magic-link-for-user

Convenience action that creates/retrieves the user and then generates
a magic link in one step. Does not require C<--api-key>.

Required options: C<--api-token>, C<--api-token-expires-at>,
C<--partner-api-url>, C<--target-domain>.

Optional options: C<--user-name>, C<--user-email>, C<--user-tracking-id>,
C<--locale>, C<--return-url>.

=item --send-webhook-event

Post a WP2 → Nova webhook event for an import outcome.  Wire-level
event type (C<import.succeeded> / C<import.failed>) is derived from
C<--status>.  Requires C<--api-key>.

Required options: C<--api-key>, C<--target-domain>, C<--status>
(C<success> or C<failed>).

Optional options: C<--error> (typically only with C<--status=failed>),
C<--occurred-at> (Unix epoch seconds; defaults to now).

=item --send-webhook-event-for-user

Convenience action that retrieves the partner user's API key
(idempotently, via C<create-user>) and then posts the webhook event
in one step. Does not require C<--api-key>.

Required options: C<--target-domain>, C<--status>.

Optional options: C<--user-name>, C<--user-email>, C<--locale>,
C<--error>, C<--occurred-at>.

=item --verbose

Enable verbose output.

=item --help

Display this help message.

=back

=cut

use parent qw(Cpanel::HelpfulScript);

use Cpanel::JSON                   ();
use Cpanel::WP::Nova::REST::Client ();

__PACKAGE__->new(@ARGV)->run() unless caller;

sub _OPTIONS {
    return (
        "base-url=s",
        "timeout=i",
        "partner-id=i",
        "user-id=s",
        "user-name=s",
        "user-email=s",
        "locale=s",
        "api-key=s",
        "api-token=s",
        "api-token-expires-at=i",
        "partner-api-url=s",
        "target-domain=s",
        "user-tracking-id=s",
        "return-url=s",
        "status=s",
        "error=s",
        "occurred-at=i",
        "create-user",
        "create-magic-link",
        "create-magic-link-for-user",
        "send-webhook-event",
        "send-webhook-event-for-user",
        "verbose|v",
    );
}

my $_VERBOSE;

sub run ($self) {

    die $self->help() if $self->getopt('help');

    $self->ensure_root();

    my $dispatch = [
        [ 'create-user',                 \&_create_user ],
        [ 'create-magic-link',           \&_create_magic_link ],
        [ 'create-magic-link-for-user',  \&_create_magic_link_for_user ],
        [ 'send-webhook-event',          \&_send_webhook_event ],
        [ 'send-webhook-event-for-user', \&_send_webhook_event_for_user ],
    ];

    die $self->help() unless grep { $self->getopt( $_->[0] ) } $dispatch->@*;

    $_VERBOSE = $self->getopt('verbose') ? 1 : 0;

    my %common  = _required_args( $self, qw(base_url partner_id user_id) );
    my %optsclt = _optional_args( $self, qw(timeout) );
    my $client  = Cpanel::WP::Nova::REST::Client->new(
        base_url => delete $common{base_url},
        %optsclt,
    );

    for my $action ( $dispatch->@* ) {
        if ( $self->getopt( $action->[0] ) ) {
            $action->[1]->( $self, $client, %common );
            return;
        }
    }

    return;
}

sub _create_user ( $self, $client, %common ) {

    _verbose("Creating/retrieving partner user …");

    my $response = $client->create_user(
        %common,
        _optional_args( $self, qw(user_name user_email locale) ),
    );

    _verbose("User created/retrieved successfully.");
    _say( Cpanel::JSON::pretty_dump( $response->data() ) );

    return;
}

sub _create_magic_link ( $self, $client, %common ) {

    _verbose("Generating magic link …");

    my $response = $client->create_magic_link(
        %common,
        _required_args( $self, qw(api_key api_token api_token_expires_at partner_api_url target_domain) ),
        _optional_args( $self, qw(user_tracking_id locale return_url) ),
    );

    _verbose("Magic link generated successfully.");
    _say( Cpanel::JSON::pretty_dump( $response->data() ) );

    return;
}

sub _create_magic_link_for_user ( $self, $client, %common ) {

    _verbose("Creating/retrieving user and generating magic link …");

    my $response = $client->create_magic_link_for_user(
        %common,
        _required_args( $self, qw(api_token api_token_expires_at partner_api_url target_domain) ),
        _optional_args( $self, qw(user_name user_email user_tracking_id locale return_url) ),
    );

    _verbose("Magic link generated successfully.");
    _say( Cpanel::JSON::pretty_dump( $response->data() ) );

    return;
}

sub _send_webhook_event ( $self, $client, %common ) {

    _verbose("Notifying Nova of import outcome …");

    my $response = $client->send_webhook_event(
        %common,
        _required_args( $self, qw(api_key target_domain status) ),
        _optional_args( $self, qw(error occurred_at) ),
    );

    _verbose("Nova notified successfully.");
    _say( Cpanel::JSON::pretty_dump( $response->data() ) );

    return;
}

sub _send_webhook_event_for_user ( $self, $client, %common ) {

    _verbose("Retrieving user and notifying Nova of import outcome …");

    my $response = $client->send_webhook_event_for_user(
        %common,
        _required_args( $self, qw(target_domain status) ),
        _optional_args( $self, qw(user_name user_email locale error occurred_at) ),
    );

    _verbose("Nova notified successfully.");
    _say( Cpanel::JSON::pretty_dump( $response->data() ) );

    return;
}

# Resolve CLI option values for a list of argument names.
# Translates underscores to dashes for Getopt option lookup.
# Returns a hash of name => value for all defined options.
sub _resolve_args ( $self, @names ) {
    my %pairs;
    for my $name (@names) {
        ( my $opt = $name ) =~ tr/_/-/;
        my $val = $self->getopt($opt);
        $pairs{$name} = $val if defined $val;
    }
    return %pairs;
}

# Resolve required args, dying with help text if any are missing.
sub _required_args ( $self, @names ) {
    my %pairs   = _resolve_args( $self, @names );
    my @missing = map { ( my $opt = $_ ) =~ tr/_/-/; "--$opt" } grep { !exists $pairs{$_} } @names;
    die $self->help( "Missing required options: " . join( ', ', @missing ) . "\n" ) if @missing;
    return %pairs;
}

# Resolve optional args, returning only those that were provided.
sub _optional_args ( $self, @names ) {
    return _resolve_args( $self, @names );
}

sub _say ($message) {
    say $message;
    return;
}

sub _verbose ($msg) {
    _say($msg) if $_VERBOSE;
    return;
}

1;
