#!/usr/bin/perl

use strict;
use warnings;

use Carp qw(confess);
use Data::Dumper;
### use Sys::RunAlone;
use Getopt::Std;
use List::Util qw(shuffle);

use Ernad::Dates;
use Ernad::Presort;
#use Ernad::Report;

my %o;
&getopts('r:', \%o);

my $impna = $ARGV[0];
if(not $impna) {
  print "I need an impna argument\n";
  exit;
}

## do only one repcode
my $only_do_repcode=$o{'r'} // '';

my $max_updates = $ARGV[1] // '0';
if(not $only_do_repcode and $max_updates == 0) {
  print "You have not given me a number of models to update.\n";
  exit;
}
## set max_update to one if we have a report_to_do
elsif($only_do_repcode and $max_updates == 0) {
  $max_updates=1;
}

our $e=Ernad::Erimp->new({'impna'=>$impna,
                          'verbose'=>4});

my @repcodes;
#@repcodes=$e->get_curpu_repcodes;
## should not have allport, but may have it temporary
@repcodes=$e->list_repcodes();

## first look: count_models
my $count_models;

## maximum number of models found
my $max_models=0;

## get the model age in days
my $model_age_in_days=$e->{'conf'}->{'model_age_in_days'};
if(not $model_age_in_days) {
  confess "I need a model_age_in_days configuration.";
}

my $train_limit_by_days=$e->{'conf'}->{'train_limit_by_days'};
if(not $train_limit_by_days) {
  confess "I need a train_limit_by_days configuration";
}


my $m=Ernad::Presort::Model->new({'e'=>$e});
$m->motto('train');

 ## prepare allport
 ## copied from Ernad::Presort::Learn
 my $allport=$e->get_allport_repcode;
 if($allport) {
   ## exfits
   use Ernad::Presort::Exfit;
   my $f=Ernad::Presort::Exfit->new({'e'=>$e});
   ##$e->{'repcode'}=$repcode;
   $f->set_report($allport);
   $f->update($allport);

   ## must be set again
   $e->{'repcode'}=$allport;

   ## fideks
   use Ernad::Presort::Fidek;
   my $k=Ernad::Presort::Fidek->new({'e'=>$e});
   $k->motto('train');
   $k->update_for_report($allport);

   ## ranfis
   my $r=Ernad::Presort::Ranfi->new({'e'=>$e});
   $r->update_for_report($allport);

   ## vemlis
   my $v=Ernad::Presort::Vemli->new({'e'=>$e});
   $v->motto('train');
   $v->update_for_report($allport);
 }

## find ages for *all* reports
my $model_ages;
foreach my $repcode (shuffle @repcodes) {
  $m->{'repcode'}=$repcode;
  ## this is really for most basic security
  if(not $e->{'conf'}) {
    confess "I need this here.";
  }
  if($repcode eq $e->{'conf'}->{'allport_repcode'}) {
    next;
  }
  my $last_model_file=$m->most_recent;
  my $model_file_age=-M $last_model_file // 0;
  if(not $model_file_age and $repcode eq $only_do_repcode) {
    $m->{'repcode'}=$repcode;
    $m->run();
  }
  if(not $only_do_repcode and $model_file_age < $model_age_in_days) {
    my $note="I skip $repcode. It's model $last_model_file of age ";
    $note.="$model_file_age is too recent.\n";
    $e->echo(__LINE__,$note);
    next;
  }
  $model_ages->{$repcode}=$model_file_age;
}

my $count_renewals=0;
my $young;
if(not $only_do_repcode) {
  ## find out the young reports. This takes also care of loading the reports
  $young=&get_young_reports(\@repcodes);
  my @to_do_order;
  ## hash to avoid repetition
  my $to_do={};
  ## first run a model for reports that don't have one
  foreach my $repcode (keys %$young) {
    if($model_ages->{$repcode}) {
      next;
    }
    $to_do->{$repcode}=1;
    push(@to_do_order,$repcode);
  }
  ## update young reports as soon as we have something new
  foreach my $repcode (sort {$model_ages->{$b} <=> $model_ages->{$a}} keys %$young) {
    if($to_do->{$repcode}) {
      next;
    }
    $to_do->{$repcode}=1;
    push(@to_do_order,$repcode);
  }
  foreach my $repcode (@to_do_order) {
    if(not $e->{'r'}) {
      confess "I don't see my Recon.";
    }
    $e->{'repcode'}=$repcode;
    my $rerc=$e->{'report'}->{$repcode} // $e->{'r'}->setup($repcode)
      // confess "I can't get to $repcode.";
    my $sent_dir=$rerc->{'dir'}->{'sent'};
    ## a poor way to deal with the absence of the sent directory
    #my $last_sent_file=&Ernad::Common::get_most_recent_rif($sent_dir,'do_lax') or next;
    my $last_sent_file=$e->{'d'}->most_recent_rif($sent_dir,'do_lax') or next;
    ## this code was here, but it seems to contradict the line above
    #if(not $last_sent_file) {
    #  $count_renewals++;
    #  &run_model($repcode);
    #}
    # my $last_model_file=get_last_model_file($repcode);
    $m->{'repcode'}=$repcode;
    my $last_model_file=$m->most_recent;
    my $model_file_age=-M $last_model_file // 0;
    my $sent_file_age=-M "$sent_dir/$last_sent_file";
    if($model_file_age and $sent_file_age > $model_file_age) {
      next;
    }
    $count_renewals++;
    $e->echo(__LINE__,"I run a model for the young $repcode.");
    $m->{'repcode'}=$repcode;
    $m->run();
  }
}

## check if we have done enough
if($count_renewals >= $max_updates) {
  $e->echo(__LINE__,"I have done enough.");
  exit;
}


my @queue_reports=sort {$model_ages->{$b} <=> $model_ages->{$a}} keys %$model_ages;
foreach my $repcode (@queue_reports)  {
  if($repcode eq $e->{'conf'}->{'allport_repcode'}) {
    next;
  }
  if($only_do_repcode and ($repcode ne $only_do_repcode)) {
    next;
  }
  if($count_renewals++ >= $max_updates) {
    $e->echo(__LINE__,"I reached the maximum renewals.");
    exit;
  }
  $e->echo(__LINE__,"I run a model for the old $repcode.");
  $m->{'repeode'}=$repcode;
  $m->run();
}

exit;

sub get_young_reports {
  my $repcodes=shift;
  my @repodes=@$repcodes;
  my $young;
  foreach my $repcode (shuffle @repcodes)  {
    my $rerc=$e->{'report'}->{$repcode};
    ## don't use defined here because rerc is often {}, thus defined!
    if(not scalar keys %$rerc) {
      $e->{'r'}->load($repcode);
    }
    if(not defined($rerc)) {
      confess "I need a rerc defined here.";
    }
    #my $r=Ernad::Report->new($repcode);
    #my $age=$r->age();
    my $age=$e->{'p'}->get_age();
    if(defined($age) and $age < $train_limit_by_days) {
     pi $young->{$repcode}=1;
    }
  }
  return $young;
}


#my $l;
## make sure we don't have emtpy models
#foreach my $repcode (shuffle @repcodes)  {
#  ## this is really for most basic security
#  if(not $e->{'conf'}) {
#    confess "I need this here.";
#  }
#  if($repcode eq $e->{'conf'}->{'allport_repcode'}) {
#    confess "I should not be give the allport.";
#  }
#  $e->{'repcode'}=$repcode;
#  $l=Ernad::Learn->new({'impna' => $impna,
#                        'e' => $e,
#                        'repcode' => $repcode,
#                        'verbose' => 1});
#  my $model_glob=$l->{'mocla_dir'}.'/'.$repcode.'/*.model';
#  my @model_files=glob($model_glob);
#  foreach my $model_file (@model_files) {
#    if(-z $model_file and -M $model_file > 1)  {
#      unlink $model_file;
#    }
#  }
#}


# ## find what reports to skip
# my $report_to_skip={};
# foreach my $repcode (shuffle @repcodes)  {
#   my $model_glob=$l->{'mocla_dir'}.'/'.$repcode.'/*.model';
#   my @model_files=glob($model_glob);
#   my $i_can_skip_this_report=0;
#   my $count_found_models=scalar(@model_files) // 0;
#   if($count_found_models> $max_models) {
#     $max_models=$count_found_models;
#   }
#   $count_models->{$repcode}=$count_found_models;
#   print "$repcode has $count_found_models models\n";
#   foreach my $model_file (shuffle @model_files) {
#     if(-M $model_file < $model_age_in_days)  {
#       $report_to_skip->{$repcode}=1;
#     }
#   }
# }
#
# ## if we have a report with no model, build one and then exit
# my $urgent_modeling_done=0;
# foreach my $repcode (shuffle @repcodes)  {
#   if(not $count_models->{$repcode}) {
#     &run_model($repcode);
#     $urgent_modeling_done=1;
#   }
# }
# if($urgent_modeling_done) {
#   exit;
# }
#
# ## find the minimal ammount of models
# my $min_models=$max_models;
# foreach my $repcode (shuffle @repcodes)  {
#   if($count_models->{$repcode} < $min_models) {
#     if(not $report_to_skip->{$repcode}) {
#       $min_models=$count_models->{$repcode};
#     }
#   }
# }
#
#
# foreach my $repcode (shuffle @repcodes)  {
#   if($count_models->{$repcode} > $min_models) {
#     delete $count_models->{$repcode};
#   }
# }
#
#
# foreach my $repcode (shuffle keys %{$count_models})  {
#   if($count_renewals++ > $max_updates) {
#     exit;
#   }
#   $count_renewals++;
#   &run_model($repcode);
# }
#
#
## old definition: most recent issuedate sent - olderst issuedate sent
## on 2019-02-07 changed to age of Report i.e. today - oldest sent date
# sub get_young_reports {
#   my $repcodes=shift;
#   my @repodes=@$repcodes;
#   my $young;
#   foreach my $repcode (shuffle @repcodes)  {
#     my $rerc=$e->{'report'}->{$repcode};
#     if(not $rerc) {
#       $e->{'r'}->load($repcode);
#       $rerc=$e->{'report'}->{$repcode};
#     }
#     if(not $rerc) {
#       confess "I don't know about your report '$repcode'.";
#     }
#     my $sent_dir=$rerc->{'dir'}->{'sent'} or die;
#     my $sent_files_glob="$sent_dir/*.amf.xml.*";
#     my $min_tist=0;
#     my @sent_files=glob($sent_files_glob);
#     if(not scalar @sent_files) {
#       $young->{$repcode}=1;
#       next;
#     }
#     my $min_issuedate=&Ernad::Dates::today;
#     my $max_issuedate='0000-00-00';
#     foreach my $file (glob($sent_files_glob)) {
#       my $issuedate=&Ernad::Common::find_issuedate_from_file($file);
#       if(not $issuedate) {
#         warn "I can't find the issuedate on the file $file.";
#       }
#       if(&Ernad::Dates::compare_dates($issuedate,$min_issuedate) > 0) {
#         $min_issuedate=$issuedate;
#       }
#       if(&Ernad::Dates::compare_dates($max_issuedate,$issuedate) > 0) {
#         $max_issuedate=$issuedate;
#       }
#     }
#     my $gap=&Ernad::Dates::diff_dates($min_issuedate,$max_issuedate);
#     if($gap < $train_limit_by_days) {
#       $young->{$repcode}=1;
#     }
#   }
#   return $young;
# }

# sub get_last_model_file {
#   my $repcode=shift;
#   my $model_glob=$l->{'mocla_dir'}.'/'.$repcode.'/*.model';
#   my @model_files=glob($model_glob);
#   my $i_can_skip_this_report=0;
#   my $count_found_models=scalar(@model_files) // 0;
#   if($count_found_models> $max_models) {
#     $max_models=$count_found_models;
#   }
#   my $min_model_age=time;
#   my $last_model_file='';
#   foreach my $model_file (shuffle @model_files) {
#     if(not $last_model_file) {
#       $last_model_file=$model_file;
#     }
#     my $model_age=-M $model_file;
#     if($model_age < $min_model_age)  {
#       $min_model_age=$model_age;
#       $last_model_file=$model_file;
#     }
#   }
#   return $last_model_file;
# }

#sub run_model {
#  my $repcode=shift;
#  my $fitport=&Ernad::Learn::Common::get_fitport($l,$repcode);
#  if(not defined($l->{'m'}->{$fitport})) {
#    $l->{'m'}->{$fitport}=Ernad::Learn::Dokli->new({'impna' => $l->{'impna'},
#                                                    'e'=> $l->{'e'},
#                                                    'repcode' => $repcode,
#                                                    'verbose'=> $l->{'verbose'}});
#  }
#  $l->{'m'}->model_report($repcode);
#}


__END__;
