#!/usr/bin/perl

use strict;
use warnings;
use 5.008;
$| = 1;

use Proc::Daemon;
use File::Basename;
use Date::Calc;

use lib qw(./libs);

our $Config;
BEGIN {
    use API::Config;
    $Config = $API::Config::Config;
}
use lib ($Config->{'Website_libs'});

use ECS::Config;
use ECS::DB;
use ECS::dbConfig;
use ECS::Warehouse;
use ECS::Order;
use ECS::Order::OrderLocation;

if (not $ECS::Config::c{'sandbox'}) {
    my $daemon = Proc::Daemon->new(
        'child_STDOUT' => '>>/var/log/cleanAndExpireParkingLocation.log',
        'child_STDERR' => '>>/var/log/cleanAndExpireParkingLocation.log',
    );

    my $child_pid = $daemon->Init; # fork

    # Parent dies and child does the work
    if ($child_pid) {
        exit;
    }
}

print "Started ".fileparse(__FILE__)." \n";

my ($lastCleanParkingCronRun, $lastExpiryParkingCronRun);

while (1) {
    print "Starting Processing\n";
    my $p = init();
    $p->{'allOrderLocations'} = ECS::Order::OrderLocation::search({
        'dbh' => $p->{'dbh'},
        'search' => [],
    });
    my @orderIDs = map { $_->orderID } @{ $p->{'allOrderLocations'} };
    $p->{'orders'} = ECS::Order->loadMulti({
        'DBH' => $p->{'dbh'},
        'orderID' => \@orderIDs,
	});

    print "Found ".scalar @orderIDs." orders in parking spot\n";

    my $allowCleanup = allowProcessing({
        'interval' => $p->{'cleanParkingCronInterval'},
        'cleanup' => 1,
    });
    
    print "Marking for Cleanup would happen on this run\n" if ($allowCleanup);

    my $allowExpire = allowProcessing({
        'interval' => $p->{'expireParkingCronInterval'},
        'expire' => 1,
    });
    
    print "Marking for Expire would happen on this run\n" if ($allowExpire);

    my (@expireOrders, @cleanupOrders);
    foreach my $orderID ( keys %{ $p->{'orders'} } ) {
        my $order = $p->{'orders'}->{$orderID};
        if ($order->status eq 'Canceled' || $order->status eq 'Restock') {
            push @expireOrders, $order if ($allowExpire);
        }
        elsif (isEligibleForCleanup($order)) {
            push @cleanupOrders, $order if ($allowCleanup);
        }
        # clean expire/cleanup flag for rest of the orderLocations
        else {
            $order->orderLocation->expire('NO');
            $order->orderLocation->cleanup('NO');
            $order->orderLocation->save;
        }
    }

    print "No of expire marked orders" . scalar @expireOrders . "\n" if (@expireOrders);
    
    foreach my $order (@expireOrders) {
        $order->orderLocation->expire('YES');
        $order->orderLocation->cleanup('NO');
        $order->orderLocation->save;
    }

    print "No of cleanup marked orders" . scalar @cleanupOrders . "\n" if (@cleanupOrders);

    foreach my $order (@cleanupOrders) {
        $order->orderLocation->expire('NO');
        $order->orderLocation->cleanup('YES');
        $order->orderLocation->save;
    }
    
    print "Processing complete\n";
    sleep(60);
}

sub init {
    my $p = {};

    $p->{'dbh'} = ECS::DB->connect({'config' => $ECS::dbConfig::db{'mysql'}});
    $p->{'DBH'} = $p->{'dbh'};

    my $warehouseConfig = ECS::Warehouse::getConfig({'DBH' => $p->{'DBH'}});
    $p->{'expireParkingCronInterval'} = $warehouseConfig->{'expireParkingCronInterval'};
    $p->{'cleanParkingCronInterval'} = $warehouseConfig->{'cleanParkingCronInterval'};

    return $p;
}

sub isEligibleForCleanup {
    my $order = shift;

    return if (
        $order->status eq 'Batched'
        || $order->status eq 'Picked'
        || $order->status eq 'Picking'
    );

    my $orderLocation = $order->orderLocation;
    my $allStockedProducts = $orderLocation->allProducts;

    return if (! scalar @$allStockedProducts);

    my %orderQtys = ();
    foreach my $item (@{ $order->cartComponents }) {
        $orderQtys{$item->productID} += $item->sellingQty;
    }

    foreach my $stockedProduct (@$allStockedProducts) {
        return 1 if (
            ! exists $orderQtys{ $stockedProduct->{'productID'} }
            || $stockedProduct->{'qty'} > $orderQtys{ $stockedProduct->{'productID'} }
        );
    }

    return;
}

# check time difference
sub allowProcessing {
    my $p = shift;

    my $allow = 0;
    my $lastRunTime = $p->{'expire'}
        ? $lastExpiryParkingCronRun
        : $lastCleanParkingCronRun;

    my $time = time;
    if (! $lastRunTime) {
        $allow = 1;
    }

    if (! $allow && ($time - $lastRunTime)/60 > $p->{'interval'}) {
        $allow = 1;
    }

    if ($allow) {
        if ($p->{'expire'}) {
            $lastExpiryParkingCronRun = $time;
        } else {
            $lastCleanParkingCronRun = $time;
        }
        return 1;
    }

    return;
}
