#!/usr/bin/perl -Ilibs

package API::OffsiteStorageAdmin;

use strict;
use warnings;
use autodie;
use namespace::autoclean;

use Carp;
use Moose;
use Try::Tiny;

extends "API::Controller";

use API::Config;

use ECS::Employee;
use ECS::Warehouse::Offsite::Pallet;
use ECS::Warehouse::Offsite::Ticket;
use ECS::Warehouse::Scanner::User;

our $WAREHOUSE_ID = 2;

__PACKAGE__->meta->make_immutable;
return 1;

###############################################################################

sub search {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'templates'} = [ "index.html" ];

    # default to active pallets
    $self->input->{'palletStatusID'} = "active"
        if not defined $self->input->{'palletStatusID'};

    my %search = (
        'palletStatusID' => $self->input->{'palletStatusID'},
    );

    if($search{'palletStatusID'} eq "active") {
        my $completed = ECS::Warehouse::Offsite::Pallet::Status::byName({
            'dbh'    => $self->dbh,
            'status' => "Completed",
        });
        $search{'palletStatusID'} = { '<>' => $completed->palletStatusID };
    }
    if($self->input->{'startDate'}) {
        $search{'createdAt'} = { '>' => $self->input->{'startDate'} };
    }
    if($self->input->{'endDate'}) {
        $search{'createdAt'} = { '>' => $self->input->{'endDate'} };
    }
    if($self->input->{'requested'}) {
        $search{'requested'} = $self->input->{'requested'};
    }

    my $pallets = ECS::Warehouse::Offsite::Pallet::search({
        'dbh'    => $self->dbh,
        'search' => [
            \%search,
            {},
        ],
    });
    # only send back the IDs, the objects would just get mangled by SOAP
    $self->data->{'palletIDs'} = [ map { $_->palletID } @{ $pallets } ];

    return $self->result;
}

###############################################################################

sub newPallet {
    my $self = shift->new({'input' => shift || {}});

    my $packing = ECS::Warehouse::Offsite::Pallet::Status::byName({
        'dbh'    => $self->dbh,
        'status' => "Packing",
    });

    my $pallet = ECS::Warehouse::Offsite::Pallet->new({
        'dbh'            => $self->dbh,
        'palletStatusID' => $packing->palletStatusID,
        'employeeID'     => $self->input->{'employeeID'},
    });

    try {
        $pallet->assignLocation;
        $pallet->save;
        1;
    }
    catch {
        carp $_;
        $self->error("Failed to create pallet: $_");
        0;
    }
    or return $self->result;

    $self->data->{'labels'} = [ $pallet->labelData ];

    $self->data->{'redirect'} = "./?newPalletID=" . $pallet->palletID;

    return $self->result;
}

###############################################################################

sub getPalletDetail {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";
    $self->data->{'data'} = {};

    my $pallet;
    try {
        $pallet = ECS::Warehouse::Offsite::Pallet->new({
            'dbh'      => $self->dbh,
            'palletID' => $self->input->{'palletID'},
        });
        $pallet->products;
        1;
    }
    catch {
        $self->data->{'data'}->{'error'} = "Failed to load pallet: "
            . _shortTrace($_);
        0;
    }
    or return $self->result;

    my @products = ();
    for my $palletProduct (@{ $pallet->products }) {
        my $product = ECS::Product->new({
            'dbh'       => $self->dbh,
            'productID' => $palletProduct->productID,
        });

        my $productData = {
            map { $_ => $product->$_ } qw(
                productID
                partnumber
                description
                price_retail
                productCost
            )
        };
        $productData->{'quantity'} = $palletProduct->quantity;

        push @products, $productData;
    }

    $self->data->{'data'}->{'success'} = 1;
    $self->data->{'data'}->{'products'} = \@products;

    return $self->result;
}

###############################################################################

sub savePallets {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";
    $self->data->{'data'} = {};

    my $offsite = ECS::Warehouse::Offsite::Pallet::Status::byName({
        'dbh'    => $self->dbh,
        'status' => "Offsite",
    });

    my $palletData;
    try {
        my $json = JSON->new;
        $palletData = $json->decode($self->input->{'pallets'});
        keys %{ $palletData } > 0;
    }
    catch {
        carp $_;
        $self->data->{'data'}->{'error'} = "Unable to parse pallet data: "
            . _shortTrace($_);
        0;
    }
    or return $self->result;

    my @palletIDs = keys %{ $palletData };
    my $pallets = ECS::Warehouse::Offsite::Pallet::search({
        'dbh'    => $self->dbh,
        'search' => [
            {
                'me.palletID' => \@palletIDs,
            },
            {},
        ],
    });

    my @keepPallets = ();
    my @moveOffsite = ();
    for my $pallet (@{ $pallets }) {
        my $changes = $palletData->{ $pallet->palletID };
        $pallet->employeeID($self->input->{'employeeID'});
        
        if (
            $changes->{'requested'}
            and $changes->{'requested'} eq 'NO' # pallet requests can only be canceled
        ) {
            $pallet->requested('NO');
        }

        my $locID = $pallet->locID;
        if($changes->{'locStr'}) {
            my %locSearch = ECS::Warehouse::Location::searchParamsByLocStrings({
                'locStrings' => [ $changes->{'locStr'} ],
            });
            $locSearch{'warehouseID'} = $WAREHOUSE_ID;

            my $locations = ECS::Warehouse::Location::search({
                'dbh'    => $self->dbh,
                'search' => [
                    \%locSearch,
                    {},
                ],
            });
            my $location = $locations->[0];
            if($location) {
                $locID = $location->locID;
            }
            else {
                $self->data->{'data'}->{'error'} = "Bad location: "
                    . $changes->{'locStr'};
                return $self->result;
            }
        }
        else {
            $locID = undef;
        }

        try {
            $pallet->locID($locID);
            $pallet->palletStatusID($changes->{'status'});
            1;
        }
        catch {
            carp $_;
            $self->data->{'data'}->{'error'} = "Failed to change pallet: "
                . _shortTrace($_);
            0;
        }
        or return $self->result;
    }

    try {
        $_->save for @{ $pallets };
        1;
    }
    catch {
        carp $_;
        $self->data->{'data'}->{'error'} = "Failed to save changes: "
            . _shortTrace($_);
        0;
    }
    or return $self->result;

    $self->data->{'data'}->{'success'} = 1;

    return $self->result;
}

###############################################################################

sub viewPallet {
    my $self = shift->new({'input' => shift || {}});

    my $pallet;
    try {
        $pallet = ECS::Warehouse::Offsite::Pallet->new({
            'dbh'      => $self->dbh,
            'palletID' => $self->input->{'palletID'},
        });
        $pallet->_row;
        1;
    }
    catch {
        $self->data->{'redirect'} = ".";
        0;
    }
    or return $self->result;

    $self->data->{'templates'} = [ "viewPallet.html" ];
    $self->data->{'palletIDs'} = [ $self->input->{'palletID'} ];

    return $self->result;
}

###############################################################################

sub getLogs {
    my $self = shift->new({'input' => shift || {}});

    $self->data->{'dataType'} = "json";
    $self->data->{'data'} = {};

    my $pallet;
    try {
        $pallet = ECS::Warehouse::Offsite::Pallet->new({
            'dbh'      => $self->dbh,
            'palletID' => $self->input->{'palletID'},
        });
        $pallet->logs;
        1;
    }
    catch {
        $self->data->{'data'}->{'error'} = "Failed to load pallet: "
            . _shortTrace($_);
        0;
    }
    or return $self->result;

    my @logs = ();
    for my $log (@{ $pallet->logs }) {
        my $logData = {
            map { $_ => $log->$_ } qw(
                field
                valueOld
                valueNew
            )
        };
        $logData->{'createdAt'} = $log->createdAt->epoch;

        if($log->userType eq "employee") {
            my $employee = ECS::Employee->load({
                'DBH'        => $self->dbh,
                'employeeID' => $log->employeeID,
            });

            $logData->{'employee'} = {
                map { $_ => $employee->{$_} } qw(
                    nameFirst
                    nameLast
                    username
                )
            } if $employee;
        }
        elsif($log->userType eq "scanner") {
            my $user = ECS::Warehouse::Scanner::User->load({
                'DBH'    => $self->dbh,
                'userID' => $log->employeeID,
            });

            $logData->{'employee'} = {
                'nameFirst' => $user->{'name'},
                'nameLast'  => "",
            };
        }

        push @logs, $logData;
    }

    $self->data->{'data'}->{'success'} = 1;
    $self->data->{'data'}->{'logs'} = \@logs;

    return $self->result;
}

###############################################################################

sub printPallets {
    my $self = shift->new({'input' => shift || {}});
    $self->data->{'dataType'} = "json";
    $self->data->{'data'} = {};

    my $palletIDs;
    try {
        my $json = JSON->new;
        $palletIDs = $json->decode($self->input->{'palletIDs'});
        1;
    }
    catch {
        $self->data->{'data'}->{'error'} = "Invalid palletIDs: "
            . _shortTrace($_);
        0;
    }
    or return $self->result;

    my $pallets = ECS::Warehouse::Offsite::Pallet::search({
        'dbh'    => $self->dbh,
        'search' => [{
            'palletID' => $palletIDs,
        }],
    });
    my $employee = ECS::Employee->load({
        'DBH'        => $self->dbh,
        'employeeID' => $self->input->{'employeeID'},
    });
    my $ticket = ECS::Warehouse::Offsite::Ticket->new({
        'dbh'      => $self->dbh,
        'pallets'  => $pallets,
        'type'     => $self->input->{'type'},
        'employee' => $employee,
    });

    $self->data->{'labels'} = [ $ticket->labelData ];
    $self->data->{'offsiteStoragePrinter'} = $self->input->{offsiteStoragePrinter} if ($self->input->{offsiteStoragePrinter});

    $self->data->{'data'}->{'success'} = 1;

    return $self->result;
}

###############################################################################

sub getPalletTicket {
    my $self = shift->new({'input' => shift || {}});

    my $palletIDs;
    try {
        my $json = JSON->new;
        $palletIDs = $json->decode($self->input->{'palletIDs'});
        1;
    }
    catch {
        carp $_;
        $self->error("Failed to create pallet: $_");
        0;
    }
    or return $self->result;

    my $employee = ECS::Employee->load({
        'DBH'        => $self->dbh,
        'employeeID' => $self->input->{'employeeID'},
    });

    $self->data->{'noHeader'} = 1;
    $self->data->{'templates'} = [ "offsiteTicket.html" ];
    $self->data->{'palletIDs'} = $palletIDs;
    $self->data->{'employeeName'} = join " ",
        $employee->nameFirst, $employee->nameLast;

    return $self->result;
}

###############################################################################
# Utility Methods                                                             #
###############################################################################

sub _shortTrace {
    my $trace = shift;

    $trace =~ s/ at \/.*//s;

    return $trace;
}

###############################################################################

