package NGCP::Panel::Utils::Interception;

use warnings;
use strict;

use Data::Dumper;
use LWP::UserAgent;
use TryCatch;
use JSON;

sub request {
    my ($c, $method, $uuid, $data) = @_;

    my $a = _init($c);
    return unless($a);

    return unless($method eq 'POST' || $method eq 'PUT' || $method eq 'DELETE');

    my @agents = @{ $a->{ua} };
    my @urls = @{ $a->{url} };
    for(my $i = 0; $i < scalar(@agents); ++$i) {
        my $ua = $agents[$i];
        my $url = $urls[$i];
        if($method eq 'PUT' or $method eq 'DELETE') {
            return unless($uuid);
            $url .= '/'.$uuid;
        }
        $c->log->debug("performing $method for interception at $url");
        try {
            _request($c, $ua, $url, $method, $data);
        } catch($e) {
            # skip errors
        }
    }
    return 1;
}

sub _request {
    my ($c, $ua, $url, $method, $data) = @_;

    my $req = HTTP::Request->new($method => $url);
    if($data) {
        $req->content_type('application/json');
        $req->content(encode_json($data));
    }
    my $res = $ua->request($req);
    if($res->is_success) {
        return 1;
    } else {
        $c->log->error("Failed to do $method on $url: " . $res->status_line);
        return;
    }
}

sub _init {
    my ($c) = @_;

    my @ua = ();
    my @url = ();
    my @cfgs = ();
    if(ref $c->config->{intercept}->{agent} eq 'HASH') {
        push @cfgs, $c->config->{intercept}->{agent};
    } elsif(ref $c->config->{intercept}->{agent} eq 'ARRAY') {
        @cfgs = @{ $c->config->{intercept}->{agent} };
    }
    unless(@cfgs) {
        $c->log->error("No intercept agents configured in ngcp_panel.conf, rejecting request");
        return;
    }
    foreach my $cfg(@cfgs) {
        my $agent = LWP::UserAgent->new();
        $agent->agent("Sipwise NGCP X1/0.2");
        $agent->timeout(2);
        if($cfg->{user} && $cfg->{pass}) {
            $agent->credentials(
                $cfg->{host}.":".$cfg->{port},
                $cfg->{realm},
                $cfg->{user},
                $cfg->{pass}
            );
        }
        push @ua, $agent;
        push @url, $cfg->{schema}.'://'.$cfg->{host}.':'.$cfg->{port}.$cfg->{url};
    }
    return { ua => \@ua, url => \@url };
}

sub username_to_regexp_pattern {

    my ($c,$voip_number,$username) = @_;

    # $c is intended to use $c->config vars here.
    # vsc.clir_code is not part of the panel conf, so
    # the global conf would be required to load to get it.
    # as this is not done elsewhere in panel code yet, we leave
    # that as todo for now, and capture any vsc codes.
    my $vsc_pattern = '(\*\d+\*)?';
    #my $vsc_pattern = '(\*31\*)?';

    my @pattern_elements = ();
    # longest to shortest:

    #1. the sip username itself:
    push(@pattern_elements,$vsc_pattern . quotemeta($username));
    #2. "international format": concat(concat('00',cc),ac,sn):
    push(@pattern_elements,$vsc_pattern . '00' . $voip_number->cc . $voip_number->ac . $voip_number->sn);
    #3. "e164 format": concat(cc,ac,sn):
    push(@pattern_elements,$vsc_pattern . $voip_number->cc . $voip_number->ac . $voip_number->sn);
    #4. "local format": concat(concat('0',ac),sn):
    push(@pattern_elements,$vsc_pattern . '0' . $voip_number->ac . $voip_number->sn);

    return '^(' . join('|',@pattern_elements) . ')$';

}

sub subresnum_from_number {
    my ($c, $number, $err_code) = @_;
    if (!defined $err_code || ref $err_code ne 'CODE') {
        $err_code = sub { return 0; };
    }
    my $num_rs = $c->model('DB')->resultset('voip_numbers')->search(
        \[ 'concat(cc,ac,sn) = ?', [ {} => $number ]]
    )->search({
        'subscriber_id' => { '!=' => undef },
    },undef);
    unless($num_rs->first) {
        return 0 unless &{$err_code}("invalid number '" . $number . "'",'number',"Number does not exist");
    }
    my $sub = $num_rs->first->subscriber;
    unless($sub) {
        return 0 unless &{$err_code}("invalid number '" . $number . "', not assigned to any subscriber",'number',"Number is not active");
    }

    my $res = $num_rs->first->reseller;
    unless($res) {
        # with ossbss provisioning, reseller is not set on number,
        # so take the long way here
        $res = $sub->contract->contact->reseller;
        unless($res) {
            return 0 unless &{$err_code}("invalid number '" . $number . "', not assigned to any reseller",'number',"Number is not active");
        }
    }

    return ($sub, $res, $num_rs->first);
}

1;
