package CF2022::Controller::Orders;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::UserAgent;

use constant MAIN_PRODUCTS        => qr/^(1|2|3)$/; # typy akreditace
use constant NONFREE_PRODUCTS     => qr/^(1)$/;     # akreditace vyzadujici token
use constant SUBSIDY_PRUDUCTS     => qr/^(58)$/;    # prispevkove polozky
use constant FALLBACK_PRODUCT     => 2;             # fallback akreditace

use feature 'signatures';
no warnings qw{ experimental::signatures };

sub create ($c ) {
    $c->openapi->valid_input or return;

    my $args      = $c->req->json;
    my $claims;
    my $group;
    my @products      = ();
    my $accredited    = 0;
    my $accreditation = 0;

    my $url = sprintf ('%s/organizers/%s/events/%s/orders/',
        $c->config->{pretix_api},
        $c->config->{pretix_organizer},
        $c->config->{pretix_event},
    );

    my @answers = map {{
        question => $_->{question_id},
        answer   => $_->{response},
    }} @{ $args->{responses} };

    # processing tokenu

    if ( $args->{token} ) {
        $c->oauth_token($args->{token});

        $claims = $c->oauth_claims;
        return $c->error(403, 'Invalid token') if ! $claims;

        $group = $c->oauth_main_group;
        return $c->error(403, 'Invalid token') if ! $group;

        $args->{name} = $claims->{name};

        push @answers, (
            {
                question => $c->config->{pretix_qid_sso},
                answer   => $claims->{sub},
            },
            {
                question => $c->config->{pretix_qid_region},
                answer   => $group->{region},
            },
        );

        $accreditation = $c->config->{'pretix_product_' . $group->{role}};

        if ( $group->{role} eq 'member' ) {
            $args->{email} = $claims->{preferred_username}
                           .'@'. $c->config->{mail_domain};
        }
        else {
            $args->{email} = $claims->{email};
        }
    }

    # korekce akreditace

    PRODUCT:
    foreach my $product ( @{ $args->{products} } ) {

        next PRODUCT if $product->{id} =~ SUBSIDY_PRUDUCTS && ! $product->{price};

        if ( $product->{id} =~ MAIN_PRODUCTS ) {
            next PRODUCT if $accredited++; # neumoznit dvoji akreditace

            if ( $accreditation ) {
                $product->{id} = $accreditation;
            }
            elsif ($product->{id} =~ NONFREE_PRODUCTS) {
                $product->{id} = FALLBACK_PRODUCT;
            }
        }

        push @products, $product;

    }

    # fallback akreditace
    @products = ( { id => FALLBACK_PRODUCT}, @products ) if ! $accredited;

    my $order = {
        email            => $args->{email},
        locale           => 'en',
        payment_provider => 'manual',
        testmode         => $c->config->{pretix_testmode} ? 'true' : 'false',
        positions        => [],
        fees             => [],
    };

    PRODUCT:
    foreach my $product ( @products ) {

        my $item = {
            item          => $product->{id},
            variation     => $product->{variation},
            attendee_name => $args->{name},
            price         => $product->{price},
            company       => $args->{company},
        };

        $item->{answers} = \@answers if $product->{id} =~ MAIN_PRODUCTS;

        push @{ $order->{positions} }, $item;
    }

    # kontrola duplicity

    my $exists = $c->schema->resultset('Order')->search({
        email => $order->{email},
        api   => $url,
    })->count;

    $exists ||= $c->schema->resultset('Order')->search({
        sso_uuid => $claims->{sub},
        api      => $url,
    })->count if $claims;

    return $c->error(400, 'Duplicity' ) if $exists;

    # odeslani do pretixu

    my $ua = Mojo::UserAgent->new;
    my $rc = $ua->post( $url,
        { Authorization => 'Token ' . $c->config->{pretix_token} },
        json => $order
    )->result;

    return $c->error(400, $rc->body) if ! $rc->is_success;

    # ukladani do lokalni databazi

    $c->schema->resultset('Order')->create({
        ip       => $c->tx->remote_address,
        sso_uuid => $claims->{sub},
        email    => $order->{email},
        api      => $url,
        request  => $order,
        order_id => $rc->json->{code},
    });

    $c->render(
        status => 201,
        json   => $rc->json,
    );
}

sub exists ($c ) {
    $c->openapi->valid_input or return;

    my $key = $c->param('key');

    my $field = ( $key =~ /\@/ ) ? 'email' : 'sso_uuid';

    my $exists = $c->schema->resultset('Order')->search({
        deleted => undef,
        $field  => $key,
    })->count;

    $c->render(
        status => 200,
        openapi => { exists => $exists },
    );
}

sub get ($c ) {
    $c->openapi->valid_input or return;

    $c->oauth_token($c->tx->req->content->headers->header('X-Token'));

    my $claims = $c->oauth_claims;
    return $c->error(403, 'Invalid token') if ! $claims;

    my $order = $c->schema->resultset('Order')->search({
        deleted  => undef,
        sso_uuid => $claims->{sub},
    })->first;

    return $c->error(404, 'NOT FOUND') if ! $order;

    # datas z pretixu

    $c->app->log->error($order->api . $order->order_id);
    my $ua = Mojo::UserAgent->new;
    my $rc = $ua->get( $order->api . $order->order_id . '/',
        { Authorization => 'Token ' . $c->config->{pretix_token} },
    )->result;

    return $c->error(400, $rc->body) if ! $rc->is_success;

    $c->render(
        status => 200,
        openapi => { order => $rc->json },
    );
}

1;