#!/usr/bin/perl -Ilibs

use strict;
use warnings;

use JSON ();

use API::Controller ();

use ECS::EMail::Inventory;
use ECS::Permission;
use ECS::Product;
use ECS::GP;

package API::InventoryAdjustment;

use Try::Tiny;
use Moose;

extends 'API::Controller';

my $DEFAULT_REASON = 1;

my %ADJUST_COST_PERMISSION = (
    'category' => 'Product Admin',
    'name' => 'Edit / Inventory - Adjust Average Cost',
);

__PACKAGE__->meta->make_immutable;

return 1;

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

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

    $self->data->{'templates'} = [ "index.html" ];
    
    $self->data->{'adjustments'} = [];
    die "T" if $self->dbh == $self->dbhr;
    $self->data->{'params'} = {
        'defaultReason' => $DEFAULT_REASON,
        'reasons' => ECS::Product::Inventory::getInventoryAdjustmentReasons({ 
            'dbh' => $self->dbh,
            'dbhr'=> $self->dbhr,
            'defaultAdjustmentReason' => $DEFAULT_REASON,
        }),
        'canAdjustCost' => (ECS::Permission::get_category({
            'dbh' => $self->dbh,
            'dbhr'=> $self->dbhr,
            'employee_id' => $self->input->{'employeeID'},
            'category' => $ADJUST_COST_PERMISSION{'category'},
        })->{$ADJUST_COST_PERMISSION{'name'}}),
    };
    
    return $self->result;
}

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

sub getProductInventoryInfo {
    my $self = (shift)->new({'input' => shift || {}});
    my $productID = $self->input->{ productID };
    
    $self->data->{'dataType'} = 'json';
    
    my $product = ECS::Product->new({
        'dbhr' => $self->dbhr,
        'dbh'  => $self->dbh,
        'productID' => $productID,
    });
    
    my ($canAdjust, $error) = ECS::Product::Inventory::canAdjustStock($product);
    
    unless ($canAdjust) {
        
        $self->data->{'data'} = {
            'success' => 0,
            'message' => $error,
        };
        
        return $self->result;
    }
    
    $self->data->{'data'} = {
        'success' => 1,
        'cost' => $product->cost,
        'onhand' => $product->onHand,
    };
    
    return $self->result;
}

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

sub saveAdjustments {
    my $self = (shift)->new({'input' => shift || {}});
    
    $self->data->{'dataType'} = "json";
    
    my $employeeID = $self->input->{'employeeID'};
    my $adjustments;
    
    try {
        $adjustments = JSON::decode_json($self->input->{'adjustments'});
    };
    
    unless ($adjustments) {
        
        $self->data->{'data'} = {
            'success' => 0,
            'message' => 'Failed to receive adjustment data',
        };
        
        return $self->result;
    }
    
    # validate adjustments first
    for my $adjust (@{ $adjustments }) {
        my $productID = $adjust->{'productID'};
        
        my $product = ECS::Product->new({
            'dbh' => $self->dbh,
            'dbhr'=> $self->dbhr,
            'productID' => $productID,
        });
        
        $adjust->{'product'} = $product;
        
        my ($canAdjust, $adjError) = ECS::Product::Inventory::canAdjustStock($product);
        
        unless ($canAdjust) {
            
            $self->data->{'data'} = {
                'success' => 0,
                'message' => ('Error on ES#'.$productID.': '.$adjError),
            };
            
            return $self->result;
        }
        
        $adjust->{'adjQty'} = $adjust->{'qty'} * (-1, +1)[ $adjust->{'sign'} cmp '-' ];
        $adjust->{'oldQty'} = $product->onHand;
        $adjust->{'newQty'} = ($product->onHand + $adjust->{'adjQty'});
        
        if ($adjust->{'newQty'} < 0) {
            
            $self->data->{'data'} = {
                'success' => 0,
                'message' => (
                    'Error on ES#'.$productID.': '
                    .'This adjustment would reduce Qty below 0'
                ),
            };
            
            return $self->result;
        }
        
    }
    
    my $employeeCanAdjustCost = (ECS::Permission::get_category({
        'dbh' => $self->dbh,
        'dbhr'=> $self->dbhr,
        'employee_id' => $employeeID,
        'category' => $ADJUST_COST_PERMISSION{'category'},
    })->{$ADJUST_COST_PERMISSION{'name'}});
    
    my @inventoryAdjustmentIDs = ();
    my %adjustedProductIDs = ();
    
    # make the adjustments
    for my $adjust (@{ $adjustments }) {
        my $productID = $adjust->{'productID'};
        my $product = $adjust->{'product'};
        
        my $adjustCost;
        if (
            defined $adjust->{'cost'}
            and $employeeCanAdjustCost
        ) {
            $adjustCost = $adjust->{'cost'};
        }
        
        my $insertAdjustment = $self->dbh->prepare(
            'INSERT INTO inventoryAdjustment (
                employeeID,
                inventoryAdjustmentReasonID,
                memo
            ) VALUES (?, ?, ?)'
        );
        
        $insertAdjustment->execute(
            $employeeID,
            $adjust->{'reasonID'},
            $adjust->{'memo'},
        );
        
        my $adjID = $self->dbh->{'mysql_insertid'};
        
        my $adjError;
        my $adjustResult = try {
            $product->stockAdjustment({
                'qty' => $adjust->{'adjQty'},
                'cost' => $adjustCost,
                'reason' => 'inventoryAdjustment',
                'itemID' => $adjID,
            });
        } catch {
            $adjError = $_;
        };
        
        if ($adjError) {
            
            if(%adjustedProductIDs) {
                ECS::Cache::ProductCache::deleteProductInfo({
                    'DBH' => $self->dbh,
                    'productIDs' => [keys %adjustedProductIDs],
                });
            }
            
            if(@inventoryAdjustmentIDs) {
                ECS::GP::enqueue({
                    'action'                 => "inventoryAdjustments",
                    'inventoryAdjustmentIDs' => \@inventoryAdjustmentIDs,
                });
            }
            
            $self->data->{'data'} = {
                'success' => 0,
                'message' => ('Error on ES#'.$productID.': '.$adjError),
                'errorProductID' => $productID,
            };
            
            return $self->result;
        }
        
        $adjustedProductIDs{$productID} = 1;
        push @inventoryAdjustmentIDs, $adjID;
        
        # send adjustment report, if needed
        if ($adjustResult) {
            
            $adjustResult->{'dbh'} = $self->dbh;
            $adjustResult->{'employeeID'} = $employeeID;
            
            my $getEmailDetails = $self->dbhr->prepare(
                "SELECT
                    CONCAT(nameFirst, ' ', nameLast) AS employeeName,
                    inventoryAdjustmentReason.description AS reasonText 
                FROM
                    employeeInfo,
                    inventoryAdjustmentReason
                WHERE
                    employeeInfo.employeeID = ?
                    AND inventoryAdjustmentReason.inventoryAdjustmentReasonID = ?"
            );
            
            $getEmailDetails->execute(
                $employeeID,
                $adjust->{'reasonID'},
            );
            
            if (my $row = $getEmailDetails->fetchrow_hashref()) {
                $adjustResult->{'employeeName'} = $row->{'employeeName'};
                $adjustResult->{'reasonText'} = $row->{'reasonText'};
            }
            
            ECS::EMail::Inventory::emailInventoryAdjustment($adjustResult);
        }
    }
    
    if(@inventoryAdjustmentIDs) {
        ECS::GP::enqueue({
            'action'                 => "inventoryAdjustments",
            'inventoryAdjustmentIDs' => \@inventoryAdjustmentIDs,
        });
    }
    
    if(%adjustedProductIDs) {
        ECS::Cache::ProductCache::deleteProductInfo({
            'DBH' => $self->dbh,
            'productIDs' => [keys %adjustedProductIDs],
        });
    }
    
    $self->data->{'data'} = {
        'success' => 1,
    };
    
    return $self->result;
}

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

