#!/usr/bin/perl

# Copyright 2000-2002 Katipo Communications
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <https://www.gnu.org/licenses>.

use Modern::Perl;

use CGI   qw ( -utf8 );
use POSIX qw( ceil );

use C4::Context;
use C4::Output      qw( output_html_with_http_headers );
use C4::Auth        qw( get_template_and_user );
use C4::Acquisition qw/GetOrdersByBiblionumber/;
use Koha::DateUtils qw( dt_from_string );
use Koha::Acquisition::Baskets;

my $input             = CGI->new;
my $startdate         = $input->param('from');
my $enddate           = $input->param('to');
my $ratio             = $input->param('ratio');
my $include_ordered   = $input->param('include_ordered');
my $include_suspended = $input->param('include_suspended');

my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
    {
        template_name => "circ/reserveratios.tt",
        query         => $input,
        type          => "intranet",
        flagsrequired => { circulate => "circulate_remaining_permissions" },
    }
);

my $booksellerid = $input->param('booksellerid') // '';
my $basketno     = $input->param('basketno')     // '';
if ( $booksellerid && $basketno ) {
    $template->param( booksellerid => $booksellerid, basketno => $basketno );
}

my $effective_create_items = q{};
if ($basketno) {
    my $basket = Koha::Acquisition::Baskets->find($basketno);
    if ($basket) {
        $effective_create_items = $basket->effective_create_items;
    } else {
        $effective_create_items = C4::Context->preference('AcqCreateItem');
    }
}

my $todaysdate = dt_from_string;

#    A default of the prior years's holds is a reasonable way to pull holds
$enddate   = $todaysdate                                unless $enddate;
$startdate = $todaysdate->clone->subtract( years => 1 ) unless $startdate;

if ( !defined($ratio) ) {
    $ratio = C4::Context->preference('HoldRatioDefault');
}

# Force to be a number
$ratio += 0;
if ( $ratio <= 0 ) {
    $ratio = 1;    # prevent division by zero
}

my $dbh          = C4::Context->dbh;
my $sqldatewhere = "";
my @query_params = ();

$sqldatewhere .= " AND reservedate >= ?";
push @query_params, $startdate;
$sqldatewhere .= " AND reservedate <= ?";
push @query_params, $enddate;

my $include_aqorders_qty =
    $effective_create_items eq 'receiving'
    ? '+ COALESCE(aqorders.quantity, 0) - COALESCE(aqorders.quantityreceived, 0)'
    : q{};

my $include_aqorders_qty_join =
    $effective_create_items eq 'receiving'
    ? 'LEFT JOIN aqorders ON reserves.biblionumber=aqorders.biblionumber'
    : q{};

my $nfl_comparison = $include_ordered   ? '<=' : '=';
my $sus_comparison = $include_suspended ? '<=' : '<';
my $strsth         = "SELECT reserves.biblionumber,
        GROUP_CONCAT(DISTINCT items.itemcallnumber 
            ORDER BY items.itemnumber SEPARATOR '|') as listcall,
        GROUP_CONCAT(DISTINCT homebranch
            ORDER BY items.itemnumber SEPARATOR '|') as homebranch_list,
        GROUP_CONCAT(DISTINCT holdingbranch 
            ORDER BY items.itemnumber SEPARATOR '|') as holdingbranch_list,
        GROUP_CONCAT(DISTINCT items.location 
            ORDER BY items.itemnumber SEPARATOR '|') as l_location,
        GROUP_CONCAT(DISTINCT items.itype 
            ORDER BY items.itemnumber SEPARATOR '|') as l_itype,
        GROUP_CONCAT(DISTINCT items.ccode
            ORDER BY items.ccode SEPARATOR '|') as l_ccode,
        biblio.title,
        biblio.subtitle,
        biblio.medium,
        biblio.part_number,
        biblio.part_name,
        biblio.author,
        count(DISTINCT reserves.borrowernumber) as reservecount, 
        count(DISTINCT items.itemnumber) $include_aqorders_qty as itemcount
 FROM  reserves
 LEFT JOIN items ON items.biblionumber=reserves.biblionumber 
 LEFT JOIN biblio ON reserves.biblionumber=biblio.biblionumber
 $include_aqorders_qty_join
 WHERE
 notforloan $nfl_comparison 0 AND damaged = 0 AND itemlost = 0 AND withdrawn = 0
 AND suspend $sus_comparison 1
 $sqldatewhere
";

if ( C4::Context->preference('IndependentBranches') ) {
    $strsth .= " AND items.holdingbranch=? ";
    push @query_params, C4::Context->userenv->{'branch'};
}

$strsth .= " GROUP BY reserves.biblionumber, biblio.title, biblio.subtitle,
    biblio.medium, biblio.part_number, biblio.part_name, biblio.author
    ORDER BY reservecount DESC
";

$template->param( sql => $strsth );
my $sth = $dbh->prepare($strsth);
$sth->execute(@query_params);

my @reservedata;
while ( my $data = $sth->fetchrow_hashref ) {
    my $thisratio     = $data->{reservecount} / $data->{itemcount};
    my $copies_to_buy = ceil( $data->{reservecount} / $ratio - $data->{itemcount} );
    $thisratio >= $ratio or next;    # TODO: tighter targeting -- get ratio limit into SQL using HAVING clause
    push(
        @reservedata,
        {
            title              => $data->{title},
            subtitle           => $data->{subtitle},
            medium             => $data->{medium},
            part_number        => $data->{part_number},
            part_name          => $data->{part_name},
            author             => $data->{author},
            biblionumber       => $data->{biblionumber},
            homebranch_list    => [ split( '\|', $data->{homebranch_list} ) ],
            holdingbranch_list => [ split( '\|', $data->{holdingbranch_list} ) ],
            location           => [ split( '\|', $data->{l_location} ) ],
            itype              => [ split( '\|', $data->{l_itype} ) ],
            ccode              => [ split( '\|', $data->{l_ccode} ) ],
            reservecount       => $data->{reservecount},
            itemcount          => $data->{itemcount},
            copies_to_buy      => sprintf( "%d",   $copies_to_buy ),
            thisratio          => sprintf( "%.2f", $thisratio ),
            thisratio_atleast1 => ( $thisratio >= 1 ) ? 1 : 0,
            listcall           => [ split( '\|', $data->{listcall} ) ]
        }
    );
}

for my $rd (@reservedata) {
    next unless $rd->{biblionumber};
    $rd->{pendingorders} = CountPendingOrdersByBiblionumber( $rd->{biblionumber} );
}

$template->param(
    todaysdate        => $todaysdate,
    from              => $startdate,
    to                => $enddate,
    ratio             => $ratio,
    include_ordered   => $include_ordered,
    include_suspended => $include_suspended,
    reserveloop       => \@reservedata,
);

output_html_with_http_headers $input, $cookie, $template->output;

sub CountPendingOrdersByBiblionumber {
    my $biblionumber = shift;
    my @orders       = GetOrdersByBiblionumber($biblionumber);
    my $cnt          = 0;
    if ( scalar(@orders) ) {
        for my $order (@orders) {
            next if $order->{datecancellationprinted};
            my $onum = $order->{quantity}         // 0;
            my $rnum = $order->{quantityreceived} // 0;
            next if $rnum >= $onum;
            $cnt += ( $onum - $rnum );
        }
    }
    return $cnt;
}
