package NGCP::Panel::Controller::Package;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;

use parent 'Catalyst::Controller';

use NGCP::Panel::Form;

use NGCP::Panel::Utils::Message;
use NGCP::Panel::Utils::Navigation;
use NGCP::Panel::Utils::ProfilePackages qw();
use NGCP::Panel::Utils::Voucher qw();

sub auto :Private {
    my ($self, $c) = @_;
    $c->log->debug(__PACKAGE__ . '::auto');
    NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
    return 1;
}

sub package_list :Chained('/') :PathPart('package') :CaptureArgs(0) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) :AllowedRole(ccareadmin) :AllowedRole(ccare) {
    my ($self, $c) = @_;

    my $dispatch_role = $c->user->roles =~ /admin$/ ? 'admin' : 'reseller';
    my $dispatch_to = '_package_resultset_' . $dispatch_role;
    my $package_rs = $self->$dispatch_to($c);

    $c->stash->{package_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
        { name => 'id', search => 1, title => $c->loc('#') },
        { name => 'reseller.name', search => 1, title => $c->loc('Reseller') },
        { name => 'name', search => 1, title => $c->loc('Name') },
        NGCP::Panel::Utils::ProfilePackages::get_datatable_cols($c),
    ]);

    $c->stash(package_rs   => $package_rs,
              template => 'package/list.tt');
}

sub package_list_restricted :Chained('package_list') :PathPart('') :CaptureArgs(0) :Does(License) :RequiresLicense('billing') :LicenseDetachTo('/denied_page') :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
    my ($self, $c) = @_;
}

sub _package_resultset_admin {
    my ($self, $c) = @_;
    return $c->model('DB')->resultset('profile_packages')->search_rs(
        undef,
        { group_by => 'me.id',
         })->search_rs(
            undef,
            { '+select' => [ { '' => \[ NGCP::Panel::Utils::ProfilePackages::get_contract_count_stmt(10) ] , -as => 'contract_cnt' },
                             { '' => \[ NGCP::Panel::Utils::ProfilePackages::get_voucher_count_stmt() ] , -as => 'voucher_cnt' },
                             ],
            });
}

sub _package_resultset_reseller {
    my ($self, $c) = @_;

    return $c->model('DB')->resultset('admins')->find(
            { id => $c->user->id, } )
        ->reseller
        ->search_related('profile_packages')->search_rs(
        undef,
        { group_by => 'me.id',
         })->search_rs(
            undef,
            { '+select' => [ { '' => \[ NGCP::Panel::Utils::ProfilePackages::get_contract_count_stmt(10) ] , -as => 'contract_cnt' },
                             { '' => \[ NGCP::Panel::Utils::ProfilePackages::get_voucher_count_stmt() ] , -as => 'voucher_cnt' },
                             ],
            });
}

sub root :Chained('package_list') :PathPart('') :Args(0) {
    my ($self, $c) = @_;
}

sub create :Chained('package_list_restricted') :PathPart('create') :Args(0) {
    my ($self, $c) = @_;

    my $posted = ($c->request->method eq 'POST');
    my $form;
    if($c->user->is_superuser) {
        $form = NGCP::Panel::Form::get("NGCP::Panel::Form::ProfilePackage::Admin", $c);
    } else {
        $form = NGCP::Panel::Form::get("NGCP::Panel::Form::ProfilePackage::Reseller", $c);
    }
    my $params = {};
    $params = merge($params, $c->session->{created_objects});
    $form->process(
        posted => $posted,
        params => $c->request->params,
        item => $params,
    );
    NGCP::Panel::Utils::Navigation::check_form_buttons(
        c => $c,
        form => $form,
        fields => {
            'reseller.create' => $c->uri_for('/reseller/create'),
        },
        back_uri => $c->req->uri,
    );
    if($posted && $form->validated) {
        try {
            $form->values->{reseller_id} = ($c->user->is_superuser ? $form->values->{reseller}{id} : $c->user->reseller_id);
            delete $form->values->{reseller};
            foreach(qw/balance_interval timely_duration/){
                $form->values->{$_.'_unit'} = $form->values->{$_}{unit} || undef;
                $form->values->{$_.'_value'} = $form->values->{$_}{value} || undef;
                delete $form->values->{$_};
            }
            my @mappings_to_create = ();
            push(@mappings_to_create,@{delete $form->values->{initial_profiles}});
            push(@mappings_to_create,@{delete $form->values->{underrun_profiles}});
            push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
            $c->model('DB')->schema->txn_do( sub {
                my $profile_package = $c->model('DB')->resultset('profile_packages')->create($form->values);
                foreach my $mapping (@mappings_to_create) {
                    $profile_package->profiles->create($mapping);
                }
                delete $c->session->{created_objects}->{reseller};
                $c->session->{created_objects}->{package} = { id => $profile_package->id };
            });

            NGCP::Panel::Utils::Message::info(
                c => $c,
                desc => $c->loc('Profile package successfully created'),
            );
        } catch ($e) {
            NGCP::Panel::Utils::Message::error(
                c => $c,
                error => $e,
                desc  => $c->loc('Failed to create profile package.'),
            );
        }
        NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/package'));
    }

    my $target =
        NGCP::Panel::Utils::Navigation::select_back_target(
            $c, $c->uri_for('/package')
    );

    $c->stash(
        close_target => $target,
        create_flag => 1,
        form => $form
    );
}

sub base :Chained('/package/package_list_restricted') :PathPart('') :CaptureArgs(1) {
    my ($self, $c, $package_id) = @_;

    unless($package_id && is_int($package_id)) {
        $package_id //= '';
        NGCP::Panel::Utils::Message::error(
            c => $c,
            data => { id => $package_id },
            desc => $c->loc('Invalid package id detected'),
        );
        $c->response->redirect($c->uri_for());
        $c->detach;
        return;
    }

    my $res = $c->stash->{package_rs}->find($package_id);
    unless(defined($res)) {
        NGCP::Panel::Utils::Message::error(
            c => $c,
            desc => $c->loc('Profile package does not exist'),
        );
        $c->response->redirect($c->uri_for());
        $c->detach;
        return;
    }

    $c->stash(package        => {$res->get_inflated_columns},
              initial_profiles => [ map { { $_->get_inflated_columns }; } $res->initial_profiles->all ],
              underrun_profiles => [ map { { $_->get_inflated_columns }; } $res->underrun_profiles->all ],
              topup_profiles => [ map { { $_->get_inflated_columns }; } $res->topup_profiles->all ],
              package_result => $res);
}

sub edit :Chained('base') :PathPart('edit') :Args(0) {
    my ($self, $c) = @_;

    my $posted = ($c->request->method eq 'POST');
    my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::ProfilePackage::Reseller", $c);
    my $params = $c->stash->{package};
    $params->{initial_profiles} = $c->stash->{initial_profiles};
    $params->{underrun_profiles} = $c->stash->{underrun_profiles};
    $params->{topup_profiles} = $c->stash->{topup_profiles};
    $params->{reseller}{id} = delete $params->{reseller_id};
    foreach(qw/balance_interval timely_duration/){
        $params->{$_} = { unit => delete $params->{$_.'_unit'}, value => delete $params->{$_.'_value'} };
    }
    $params = merge($params, $c->session->{created_objects});
    $form->process(
        posted => $posted,
        params => $c->request->params,
        item => $params,
    );
    #remove submitid
    NGCP::Panel::Utils::Navigation::check_form_buttons(
        c => $c,
        form => $form,
        fields => {
            'reseller.create' => $c->uri_for('/reseller/create'),
        },
        back_uri => $c->req->uri,
    );
    if($posted && $form->validated) {
        try {
            foreach(qw/balance_interval timely_duration/){
                $form->values->{$_.'_unit'} = $form->values->{$_}{unit} || undef;
                $form->values->{$_.'_value'} = $form->values->{$_}{value} || undef;
                delete $form->values->{$_};
            }
            my @mappings_to_create = ();
            push(@mappings_to_create,@{delete $form->values->{initial_profiles}});
            push(@mappings_to_create,@{delete $form->values->{underrun_profiles}});
            push(@mappings_to_create,@{delete $form->values->{topup_profiles}});
            $c->model('DB')->schema->txn_do( sub {

                my $profile_package = $c->stash->{'package_result'}->update($form->values);
                $profile_package->profiles->delete;
                foreach my $mapping (@mappings_to_create) {
                    $profile_package->profiles->create($mapping);
                }
            });
            NGCP::Panel::Utils::Message::info(
                c => $c,
                desc  => $c->loc('Profile package successfully updated'),
            );
        } catch ($e) {
            NGCP::Panel::Utils::Message::error(
                c => $c,
                error => $e,
                desc  => $c->loc('Failed to update profile package'),
            );
        }

        NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/package'));

    }

    my $target =
        NGCP::Panel::Utils::Navigation::select_back_target(
            $c, $c->uri_for('/package')
    );

    $c->stash(
        close_target => $target,
        edit_flag => 1,
        form => $form
    );
}

sub delete_package :Chained('base') :PathPart('delete') :Args(0) {
    my ($self, $c) = @_;
    my $package = $c->stash->{package_result};

    try {
        #todo: putting the package fetch into a transaction wouldn't help since the count columns a prone to phantom reads...
        unless($package->get_column('contract_cnt') == 0) {
            die(['Cannnot delete profile package that is still assigned to contracts', "showdetails"]);
        }
        unless($package->get_column('voucher_cnt') == 0) {
            die(['Cannnot delete profile package that is assigned to vouchers', "showdetails"]);
        }

        $package->delete;
        NGCP::Panel::Utils::Message::info(
            c => $c,
            data => $c->stash->{package},
            desc => $c->loc('Profile package successfully deleted'),
        );
    } catch ($e) {
        NGCP::Panel::Utils::Message::error(
            c => $c,
            error => $e,
            data  => $c->stash->{package},
            desc  => $c->loc('Failed to delete profile package'),
        );
    };
    NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/package'));
}

sub ajax :Chained('package_list') :PathPart('ajax') :Args(0) {
    my ($self, $c) = @_;

    my $resultset = $c->stash->{package_rs};
    NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{package_dt_columns});
    $c->detach( $c->view("JSON") );
}

sub ajax_filter_reseller :Chained('package_list') :PathPart('ajax/filter_reseller') :Args(1) {
    my ($self, $c, $reseller_id) = @_;

    my $resultset = $c->stash->{package_rs}->search({
        'me.reseller_id' => $reseller_id,
    });
    NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{package_dt_columns});
    $c->detach( $c->view("JSON") );
}


sub details_base :Chained('/') :PathPart('package') :CaptureArgs(1) :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
    my ($self, $c, $package_id) = @_;

    my $dispatch_role = $c->user->roles =~ /admin$/ ? 'admin' : 'reseller';
    my $dispatch_to = '_package_resultset_' . $dispatch_role;
    my $package_rs = $self->$dispatch_to($c);

    unless($package_id && is_int($package_id)) {
        $package_id //= '';
        NGCP::Panel::Utils::Message::error(
            c => $c,
            data => { id => $package_id },
            desc => $c->loc('Invalid package id detected'),
        );
        $c->response->redirect($c->uri_for());
        $c->detach;
        return;
    }

    my $res = $package_rs->find($package_id);
    unless(defined($res)) {
        NGCP::Panel::Utils::Message::error(
            c => $c,
            desc => $c->loc('Profile package does not exist'),
        );
        $c->response->redirect($c->uri_for());
        $c->detach;
        return;
    }

    $c->stash->{profile_set_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
        #{ name => 'id', search => 1, title => $c->loc('#') },
        { name => 'billing_profile.name', search => 1, title => $c->loc('Billing Profile') },
        { name => 'billing_network.name', search => 1, title => $c->loc('Billing Network') },
    ]);
    $c->stash->{customer_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
        NGCP::Panel::Utils::ProfilePackages::get_customer_datatable_cols($c)
    ]);
    $c->stash->{voucher_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [
        NGCP::Panel::Utils::Voucher::get_datatable_cols($c,1)
    ]);

    $c->stash(package_result => $res);
}

sub details :Chained('details_base') :PathPart('details') :Args(0) {
    my ($self, $c) = @_;
    $c->stash(template => 'package/details.tt');
}

sub details_ajax :Chained('details_base') :PathPart('ajax') :CaptureArgs(0)  {
    my ($self, $c) = @_;

}

sub ajax_initial_profiles :Chained('details_ajax') :PathPart('initial_profiles') :Args(0) {
    my ($self, $c) = @_;

    my $resultset = $c->stash->{package_result}->initial_profiles;
    NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{profile_set_dt_columns});
    $c->detach( $c->view("JSON") );
}

sub ajax_topup_profiles :Chained('details_ajax') :PathPart('topup_profiles') :Args(0) {
    my ($self, $c) = @_;

    my $resultset = $c->stash->{package_result}->topup_profiles;
    NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{profile_set_dt_columns});
    $c->detach( $c->view("JSON") );
}

sub ajax_underrun_profiles :Chained('details_ajax') :PathPart('underrun_profiles') :Args(0) {
    my ($self, $c) = @_;

    my $resultset = $c->stash->{package_result}->underrun_profiles;
    NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{profile_set_dt_columns});
    $c->detach( $c->view("JSON") );
}


1;
