package Pcore::API::Whois v0.1.3;

use Pcore -dist, -class;
use Pcore::API::Whois::Server;
use Pcore::API::Whois::Response qw[:CONST];
use Net::Whois::Raw::Data qw[];

our $DB = P->cfg->load( $ENV->share->get('/data/whois.perl') );

our $PUB_SUFFIX;

for my $pub_suffix ( keys %Net::Whois::Raw::Data::servers ) {
    $PUB_SUFFIX->{ lc $pub_suffix } = $Net::Whois::Raw::Data::servers{$pub_suffix};
}

for my $pub_suffix ( keys $DB->{pub_suffix_server}->%* ) {
    $PUB_SUFFIX->{ P->host($pub_suffix)->name } = $DB->{pub_suffix_server}->{$pub_suffix};
}

sub search ( $self, $domain, $cb = undef ) {
    my $blocking_cv = defined wantarray ? AE::cv : undef;

    my $server_host;

    my @label = split /[.]/sm, P->host($domain)->canon;

    my $query;    # domain ascii

    if ( @label > 2 ) {
        my $pub_suffix = "$label[-2].$label[-1]";

        $server_host = $PUB_SUFFIX->{$pub_suffix};

        $query = "$label[-3].$label[-2].$label[-1]" if $server_host;
    }

    if ( !$server_host ) {
        my $pub_suffix = $label[-1];

        $server_host = $server_host = $PUB_SUFFIX->{$pub_suffix};

        $query = @label == 1 ? $label[-1] : "$label[-2].$label[-1]" if $server_host;
    }

    if ( !$server_host ) {
        my $res = Pcore::API::Whois::Response->new(
            {   status => $WHOIS_NOT_SUPPORTED,
                reason => $Pcore::API::Whois::Response::STATUS_REASON->{$WHOIS_NOT_SUPPORTED}
            }
        );

        $cb->($res) if $cb;

        $blocking_cv->($res) if $blocking_cv;
    }
    else {
        Pcore::API::Whois::Server->new(
            {   host => $server_host,
                cb   => sub($server) {
                    if ( !$server || !$server->is_supported ) {
                        my $res = Pcore::API::Whois::Response->new(
                            {   status => $WHOIS_NOT_SUPPORTED,
                                reason => $Pcore::API::Whois::Response::STATUS_REASON->{$WHOIS_NOT_SUPPORTED}
                            }
                        );

                        $cb->($res) if $cb;

                        $blocking_cv->($res) if $blocking_cv;
                    }
                    else {
                        $server->request(
                            $query,
                            sub ($res) {
                                if ( $res->status == 200 ) {
                                    my $recognized;

                                    if ( $server->exceed_re ) {
                                        for my $re ( $server->{exceed_re}->@* ) {
                                            if ( $res->content->$* =~ $re ) {
                                                $recognized = 1;

                                                $res->set_status( $WHOIS_BANNED, $Pcore::API::Whois::Response::STATUS_REASON->{$WHOIS_BANNED} );

                                                last;
                                            }
                                        }
                                    }

                                    if ( !$recognized && $server->notfound_re ) {
                                        for my $re ( $server->{notfound_re}->@* ) {
                                            if ( $res->content->$* =~ $re ) {
                                                $recognized = 1;

                                                $res->set_status( $WHOIS_NOT_FOUND, $Pcore::API::Whois::Response::STATUS_REASON->{$WHOIS_NOT_FOUND} );

                                                last;
                                            }
                                        }
                                    }
                                }

                                $cb->($res) if $cb;

                                $blocking_cv->($res) if $blocking_cv;

                                return;
                            }
                        );
                    }

                    return;
                }
            }
        );
    }

    return $blocking_cv ? $blocking_cv->recv : ();
}

sub export_supported_pub_suffixes ($self) {
    my $pub_suffix;

    my $server;

    for ( keys $PUB_SUFFIX->%* ) {
        my $ps = P->host($_)->name_utf8;

        my $host = $PUB_SUFFIX->{$_};

        if ($host) {
            $server->{$host} = bless { host => $host }, 'Pcore::API::Whois::Server' if !$server->{$host};

            if ( $server->{$host}->is_supported ) {
                $pub_suffix->{$ps} = undef;
            }
            else {
                $pub_suffix->{$ps} = $server->{$host}->host;
            }
        }
    }

    for ( sort grep { $pub_suffix->{$_} } keys $pub_suffix->%* ) {
        say "$_;$pub_suffix->{$_}";
    }

    for ( sort grep { !defined $pub_suffix->{$_} } keys $pub_suffix->%* ) {
        say "$_";
    }

    return;
}

1;
## -----SOURCE FILTER LOG BEGIN-----
##
## PerlCritic profile "pcore-script" policy violations:
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
## | Sev. | Lines                | Policy                                                                                                         |
## |======+======================+================================================================================================================|
## |    3 | 16, 126, 143, 147    | References::ProhibitDoubleSigils - Double-sigil dereference                                                    |
## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
## |    3 | 20                   | Subroutines::ProhibitExcessComplexity - Subroutine "search" with high complexity score (27)                    |
## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
## |    3 | 80, 92               | ControlStructures::ProhibitDeepNests - Code structure is deeply nested                                         |
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
##
## -----SOURCE FILTER LOG END-----
__END__
=pod

=encoding utf8

=head1 NAME

Pcore::API::Whois

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 ATTRIBUTES

=head1 METHODS

=head1 SEE ALSO

=head1 AUTHOR

zdm <zdm@softvisio.net>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by zdm.

=cut
