#!/usr/bin/perl

=head1 NAME

    object-info - скрипт для удобного получения онформации о Директовских объектах

=head1 DESCRIPTION

    ./bin/object-info --cid 88700 232454

    ./bin/object-info -client 3872190 | jq .reps[0].role

    # алиас в shell
    function doi { /var/www/ppc.yandex.ru/bin/object-info $@ | format-direct-log --colored; }
    doi -l zhurs
    doi -ci 88700

=head1 OPTIONS

    -h, --help
        показать справку
    --conf=[prod|local|devtest|test|...]
        по-умолчанию - prod
        для запроса использовать указанную конфигурацию
        (для логинов, отсутствующих в базе Директа, на бетах используется mimino даже в продакшен конфигурации)

    для всех следующих опций (объектных) можно задавать несколько идентификаторов через пробелы или запятые
    вывод информации о объекте по:

    --cid - по номеру кампании

    --uid - по паспортному идентификатору пользователя

    --login - по логину
    
    --bid - по номеру баннера

    --pid - по номеру adgroup-ы

    --ClientID - по номеру клиента

    --OrderID - по номеру заказа БК

    --oauth-app-id - по id приложения OAuth

    --oauth-token - по токену OAuth

    --oauth-staff-token - по токену OAuth-Staff

=cut

use Direct::Modern;
use open ':std' => ':utf8';

use Data::Dumper;
use Getopt::Long;
use JSON;
use Path::Tiny;

use Yandex::DBShards;
use Yandex::DBTools;
use Yandex::HashUtils;
use Yandex::Interactive qw/prompt/;

use my_inc '..', for => 'protected';

BEGIN { $Settings::NO_SETTINGS_LOCAL = 1; }

use Settings;

use Primitives;
use PrimitivesIds;
use RBAC2::Extended;
use RBACElementary;
use Rbac;

run() unless caller();

sub run {
    my (@cids, @oids, @client_ids, @uids, @logins);
    my $CONF;
    my $PRETTY;
    my @data;
    GetOptions(
        "help" => sub {
            #pod2usage(1);
            system("podselect -section NAME -section DESCRIPTION -section OPTIONS $0 | pod2text-utf8");
            exit 0;
        },
        "pretty" => \$PRETTY,
        "conf=s" => \$CONF,
        (map {
            my $f = $_; 
            +"$_=s{1,}" => sub {push @data, map {+{field => $f, id => $_}} split /[\s,]/, $_[1];}
         } qw/ClientID uid login cid OrderID pid bid oauth-app-id oauth-token oauth-staff-token bb-uid bb-login/
        ),
        );

    if ($CONF) {
        my $settings_root = path($INC{"Settings.pm"})->parent;
        my ($settings_local_file) = $settings_root->children(qr/Settings$CONF\.pm/i);
        die "Unknown configuration $CONF" unless $settings_local_file;
        no warnings 'once';
        do $settings_local_file or die "Can't load $settings_local_file: $@";
    } else {
        $Yandex::DBTools::DB_USER = sub { 'direct-ro' };
        $Yandex::Blackbox::BLACKBOX_URL = 'http://blackbox-mimino.yandex.net/blackbox';
    }

    for my $d (@data) {
        my $id = $d->{id} eq '-' ? prompt("$d->{field}: ") : $d->{id};
        my $obj = get_object_info($d->{field}, $id);
        if ($PRETTY) {
            pretty_print_object($obj);
        } else {
            print_object($obj);
        }
    }
}
    
sub get_object_info {
    my ($type, $id) = @_;
    
    my %ret = ($type => $id);
    
    if ($type eq 'login') {
        $ret{uid} = get_uid_by_login2($id);
        if ($ret{uid}) {
            hash_merge \%ret, get_uid_info($ret{uid});
        }
    } elsif ($type eq 'uid') {
        hash_merge \%ret, get_uid_info($ret{uid});
    } elsif ($type eq 'ClientID') {
        hash_merge \%ret, get_client_info($id);
    } elsif ($type eq 'OrderID') {
        $ret{cid} = get_cid(OrderID => $id);
        if ($ret{cid}) {
            hash_merge \%ret, get_cid_info($ret{cid});            
        }
    } elsif ($type eq 'cid') {
        hash_merge \%ret, get_cid_info($id); 
    } elsif ($type eq 'bid') {
        hash_merge \%ret, get_bid_info($id); 
    } elsif ($type eq 'pid') {
        hash_merge \%ret, get_pid_info($id); 
    } elsif ($type eq 'oauth-app-id') {
        hash_merge \%ret, get_oauth_app_id_info($id); 
    } elsif ($type eq 'oauth-token') {
        hash_merge \%ret, get_oauth_token_info($id); 
    } elsif ($type eq 'oauth-staff-token') {
        hash_merge \%ret, get_oauth_staff_token_info($id); 
    } elsif ($type eq 'bb-uid') {
        hash_merge \%ret, get_blackbox_uid_info($id); 
    } elsif ($type eq 'bb-login') {
        hash_merge \%ret, get_blackbox_login_info($id); 
    } else {
        die "unknown type $type";
    }
    
    return \%ret;
}

sub _rbac() {
    state $rbac;
    $rbac = RBAC2::Extended->get_singleton(1);
    return $rbac;
}

sub get_uid_info {
    my ($uid) = @_;
    my $ret = get_one_line_sql(PPC(uid => $uid), "SELECT uid, rep_type, login, ClientID, fio FROM users WHERE uid = ?", $uid);
    $ret->{role} = rbac_who_is(_rbac, $uid);
    $ret->{shard} = get_shard(uid => $uid);
    $ret->{perminfo} = Rbac::get_perminfo(ClientID => $ret->{ClientID}) if $ret->{ClientID};
    force_types($ret, int => [qw/uid ClientID shard/]);
    return $ret;
}

sub get_cid_info {
    my ($cid) = @_;
    my $ret = get_one_line_sql(PPC(cid => $cid), "SELECT c.cid, c.OrderID, c.name, c.uid, c.copiedFrom, co.create_time FROM campaigns c join camp_options co using (cid) WHERE c.cid = ?", $cid);
    force_types($ret, int => [qw/cid OrderID uid copiedFrom/]);
    if ($ret && $ret->{uid}) {
        $ret->{owner} = get_uid_info(delete $ret->{uid});
    }
    return $ret;    
}

sub get_bid_info {
    my ($bid) = @_;
    my $ret = get_one_line_sql(PPC(bid => $bid), "SELECT bid, pid, cid, title, body FROM banners WHERE bid = ?", $bid);
    force_types($ret, int => [qw/bid pid cid/]);
    if ($ret && $ret->{cid}) {
        $ret->{camp} = get_cid_info(delete $ret->{cid});
    }
    return $ret;    
}

sub get_pid_info {
    my ($pid) = @_;
    my $ret = get_one_line_sql(PPC(pid => $pid), "SELECT pid, cid, group_name FROM phrases WHERE pid = ?", $pid);
    force_types($ret, int => [qw/pid cid/]);
    if ($ret && $ret->{cid}) {
        $ret->{camp} = get_cid_info(delete $ret->{cid});
    }
    return $ret;    
}

sub get_client_info {
    my ($ClientID) = @_;
    my @uids = @{get_uids(ClientID => $ClientID)};
    return {
        reps => [map {get_uid_info($_)} @uids], 
        perminfo => Rbac::get_perminfo(ClientID => $ClientID),
    };
}

sub get_oauth_app_id_info {
    my ($app_id) = @_;
    require Yandex::OAuth;
    my $info = Yandex::OAuth::oa_get_app_info($app_id);
    $info->{ctime_datetime} = localtime( $info->{ctime} );
    $info->{mtime_datetime} = localtime( $info->{mtime} );
    return $info;
}

sub get_oauth_token_info {
    my ($token) = @_;
    require Yandex::Blackbox;
    my $res = Yandex::Blackbox::bb_oauth_token($token, '127.0.0.1', $Settings::API_SERVER_PATH, [$Yandex::Blackbox::BB_LOGIN], undef, 0);
    return $res;
}

sub get_oauth_staff_token_info {
    my ($token) = @_;
    require Yandex::Blackbox;
    local $Yandex::Blackbox::BLACKBOX_URL = 'http://blackbox.yandex-team.ru/blackbox/';
    my $res = Yandex::Blackbox::bb_oauth_token($token, '127.0.0.1', $Settings::API_SERVER_PATH, [$Yandex::Blackbox::BB_LOGIN], undef, 0);
    return $res;
}

sub get_blackbox_uid_info {
    my ($uid) = @_;
    require Yandex::Blackbox;
    my $res = Yandex::Blackbox::bb_userinfo({uid => $uid}, '127.0.0.1', "direct.yandex.ru");
    return $res;
}

sub get_blackbox_login_info {
    my ($login) = @_;
    require Yandex::Blackbox;
    my $res = Yandex::Blackbox::bb_userinfo({login => $login}, '127.0.0.1', "direct.yandex.ru");
    return $res;
}

sub print_object {
    my ($obj) = @_;
    print JSON->new->canonical(1)->encode($obj), "\n";
}

sub pretty_print_object {
    my ($obj) = @_;
    print JSON->new->pretty(1)->canonical(1)->encode($obj), "\n";
}

=head2 force_types($hash, type => [fields...])

    форсирование типов в хэше

=cut
sub force_types {
    my $d = shift;
    state $convs = {
        int => sub {int $_[0]},
    };
    while(my ($type, $fields) = splice @_, 0, 2) {
        my $conv = $convs->{$type} or croak "Incorrect type $type";
        for my $f (@$fields) {
            next unless defined $d->{$f};
            $d->{$f} = $conv->($d->{$f});
        }
    }
}
