package CLMApp;
no warnings 'all';
use Mojo::Base 'Mojolicious';
# use CLMApp::Schema;
# use CLMApp::Controller::Root;
use Data::Show;
use Cwd;
use strict;
use DateTime;
use Class::Struct;
use Object::Accessor;
use CLMApp::Schema;
use ExcelExport;
use Perl6::Junction qw/ any /;
use Moose::Autobox;
use DBIx::ResultSet;
use LWP::JSON::Tiny;
use File::Basename;
use JSON;
use File::Copy qw(copy move);
use utf8;

#use Tie::STDERR '>> ' . getcwd() . '/logs/clmapp.debug.log';
#*STDERR = *STDOUT;

# struct FormElement => {type=> '$', attrs => '%', val => '$', vals => '@', labels => '%'};
# struct Form => {attrs => '%', elems => '@'};

$ENV{MOJO_INACTIVITY_TIMEOUT} = 300;
$ENV{DBIC_TRACE}="1;/home/sites/clm.dmadelivers.com/www/clmapp/logs/clmapp.log";
# Connects once for entire application. For real apps, consider using a helper
# that can reconnect on each request if necessary.
has schema => sub {
  my $c = shift;
   my $s = CLMApp::Schema->connect("dbi:mysql:host=rds1.dmadelivers.com;db=dmaclm", 'dmaclm', '3lUz1OV2!',{mysql_enable_utf8 => 1});
  # $s->storage->dbh_do(sub{ my ($s, $d, @a) = @_; $d->do("SET NAMES utf8");});

#  my $s = CLMApp::Schema->connect("dbi:mysql:host=rds1.dmadelivers.com;db=DMA", 'root', 'b3hereNOW!');
  return $s;
};

has devschema => sub {
  my $c = shift;
   my $s = CLMApp::Schema->connect("dbi:mysql:host=rds1.dmadelivers.com;db=dmaclmdev", 'dmaclm', '3lUz1OV2!',{mysql_enable_utf8 => 1});
  # $s->storage->dbh_do(sub{ my ($s, $d, @a) = @_; $d->do("SET NAMES utf8");});

#  my $s = CLMApp::Schema->connect("dbi:mysql:host=rds1.dmadelivers.com;db=DMA", 'root', 'b3hereNOW!');
  return $s;
};


# has schemadbix => sub {
#   my $c = shift;
#   my $s = DBIx::ResultSet->connect("dbi:mysql:host=rds1.dmadelivers.com;db=dmaclm", 'dmaclm', '3lUz1OV2!');
#   return $s;
# };


sub objectify {

  my $self = shift;
  my $o = shift;


  if(ref($o) eq 'HASH'){
      my $oo = Object::Accessor->new(keys %$o);
      foreach my $k (keys %$o){
        my $oov = $o->{$k};
        if(ref($oov) ne 'SCALAR' && $k ne 'options'){
          $oo->$k($self->objectify($oov));
        }else{
          $oo->$k($oov);
        }
      }
      return $oo;
  }elsif(ref($o) eq 'ARRAY'){
      my @oo;
      foreach my $oov (@$o){
        push(@oo,$self->objectify($oov));
      }
      return \@oo;
  }else{
    return $o;
  }



}

sub load_defaults{
  my $self = shift;



  # get select / radio / input / textarea default values
  my @distributorcompany = $self->db->resultset('DistributorCompany')->search({},{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'name'});
  my @distributorwarehouse = $self->db->resultset('DistributorWarehouse')->search(undef,{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'distributorwarehousename'});
  my @dmaprogrammanager = $self->db->resultset('DmaprogramManager')->search({active=>1},{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'dmaprogrammanager'});
  my @dmavp = $self->db->resultset('Dmavp')->search({active=>1},{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'dmavp'});
  my @user = $self->db->resultset('User')->search({active=>1},{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'fullname'});
  my @chainconcept = $self->db->resultset('ChainConcept')->search(undef,{order_by=>'chainconceptname', result_class=>'DBIx::Class::ResultClass::HashRefInflator'});
  my @chaingroup = $self->db->resultset('ChainGroup')->search(undef,{order_by=>'chaingroupname',result_class=>'DBIx::Class::ResultClass::HashRefInflator'});

  my @astatus = $self->db->resultset('Status')->search(undef,{result_class=>'DBIx::Class::ResultClass::HashRefInflator'});
  my @orderflag = $self->db->resultset('OrderFlag')->search(undef,{result_class=>'DBIx::Class::ResultClass::HashRefInflator'});
  my @backofficesystem = $self->db->resultset('BackOfficeSystem')->search(undef,{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'systemname'});
  my @country = $self->db->resultset('Country')->search({active=>1},{result_class=>'DBIx::Class::ResultClass::HashRefInflator', order_by=>'fullname'});

  $self->defaults({
    distributorcompany => \@distributorcompany, 
    distributorwarehouse => \@distributorwarehouse, 
    dmaprogrammanager=>\@dmaprogrammanager, 
    dmavp=>\@dmavp, 
    user=>\@user,
    chainconcept => \@chainconcept,
    chaingroup => \@chaingroup,
    astatus => \@astatus,
    backofficesystem => \@backofficesystem,
    country => \@country
    # orderflag => \@orderflag,

    });

}


# This method will run once at server start
sub startup {
  my $self = shift;

  # Documentation browser under "/perldoc"
  # $self->plugin('PODRenderer');

  $self->plugin('RenderFile');

    $self->plugin(MailException => {
        from    => 'root@dmadelivers.com',
        to      => 'dma@ace4it.com,jenisse.hernandez@dmadelivers.com,jim.szatkowski@dmadelivers.com',
        subject => 'DMA CLM Error',
        # headers => {
        #     'X-MySite' => 'crashed'
        # }, 
        stack   => 10
    });


	$self->helper(db => sub { 
    my $c = shift; 
    my $h = $c->req->url->base->host; 
    $c->stash('host', $h);
    if($h =~ /^dev/i){
      return $self->app->devschema;   
    }
    return $self->app->schema; 
  });
  # $self->helper(dbix => sub { $self->app->schemadbix });

  $self->helper(check_email_notification => sub {
      my $c = shift;
      my $customers = shift;

      # show $customers;

      my @emailn = $c->db->resultset('EmailNotification')->search({'me.active' => 1}, {result_class => 'DBIx::Class::ResultClass::HashRefInflator'});
      my @criteria = (qw/chaingroupid chaninconceptid distributorcompanyid distributorwarehouseid/);
      foreach my $e (@emailn){
        my %criteria;
        my %emails;
        foreach my $r (@criteria){
          $criteria{'me.' . $r} = $e->{$r} if $e->{$r} > 0;
        }     
# show %criteria;
        foreach my $customer (@$customers){
          $criteria{customerid} = $customer->{customerid};
          my @cs = $c->db->resultset('Customer')->search(\%criteria, {prefetch => [qw/distributor warehouse chaingrp concept/], result_class => 'DBIx::Class::ResultClass::HashRefInflator'}) or next;
          if($cs[0]){
            push(@{ $emails{ $e->{targetlist} } }, $cs[0]);
          }
        }

        foreach my $to (keys %emails){
          my $customers = $emails{$to};


# show $c->render_to_string(inline => $e->{body}, customers => $customers);

              $c->mail(
                mail   => {
		  To => $to,
                  From => $c->config->{mail}->{from}, # message NOT from sending user so messages stay in the system
                  'Reply-to' => $c->config->{mail}->{replyto},
                  Bcc    => $c->dsconfig->{mail}->{bcc},
                  Subject  => $e->{subject},
                  Data     => $c->render_to_string(inline => $e->{body}, customers => $customers),
                },
                how => $c->config->{mail}->{how},
                howargs => $c->config->{mail}->{howargs},   

              );


        }



      }










  });


  $self->helper(populate_form => sub {
      my $c = shift;
      my $f = shift;
      my $d = shift;

      $c->setup;


      foreach my $ec (@{$c->{_forms}->{$f}->eorder},@{$c->{_forms}->{$f}->sorder}){

        my $e = $c->{_forms}->{$f}->elems->$ec;
# show "ERROR: $ec NOT FOUND" if !ref($e) =~ /Object/;
        next unless $e->can('attrs');
        if($e->can('populate')){
            next unless $e->populate->defaults;
            my $def = [];

            # process DB vs default stored on app load
            if(ref($e->populate->defaults) ne ''){
              my $rsearch = {};
              # show  $e->populate;
              my $where = \@{ $e->populate->defaults->where};
              for(my $w = 0; $w < scalar(@$where); $w++){
                $rsearch->{$where->[$w]} = $e->populate->defaults->vals->[$w];
              }
              if($e->populate->defaults->can('fk') && $e->populate->defaults->fk){
                $rsearch->{$e->populate->defaults->fk} = $d->{ $e->populate->defaults->fk };
              }
              my $prefetch = $e->populate->defaults->prefetch || [];
              my $rparams =  $e->populate->defaults->options || {};
              $rparams->{result_class} = 'DBIx::Class::ResultClass::HashRefInflator';
              # show $rsearch;
              # show $rparams;
              my @c = $c->db->resultset($e->populate->defaults->module)->search($rsearch,$rparams);

              $def = \@c;


            }else{             
              $def = $c->app->defaults($e->populate->defaults);
            }
            
            my(@v,@l);
            my(@d,@dv);
            my(@ml,@mv);
            foreach my $dv (@$def){
              if($e->populate->can('metadata') && ref($e->populate->metadata) ne ''){
                my($mv,$ml) = $e->populate->metadata->($e,$dv);
                push(@mv,$mv);
                push(@ml,$ml);
              }


              #show $dv if $e->attrs->name eq 'chainconcept';
              # if(ref($e->populate->vals) eq 'CODE'){
              #   my $v = $e->populate->vals->($e,$d,$dv);
              #   push(@v,$v) if $v;
              # }else{
                push(@v,$dv->{$e->populate->vals});
              # }
              if(ref($e->populate->labels) eq 'CODE'){
                my $v = $e->populate->labels->($e,$dv);
                push(@l,$v)  if $v;
              }else{
                push(@l,$dv->{$e->populate->labels}); 
              }
              if($e->populate->can('data')){
                my %d;
                foreach my $dk (@{ $e->populate->data }){
                  $d{$dk} = $dv->{ $dk };
                }
                push(@d, \%d);
              }
            }    

            if($e->can('default')){

              $e->default($d->{$e->attrs->name});
            }elsif($e->can('defaults')){
              # if($e->type eq 'selectpicker'){
                #my @a = split(",",  $d->{$e->attrs->name}  );
                $e->defaults($d->{$e->attrs->name});
              # }  

            }

            if($e->can('vals')){
              $e->vals(\@v) if scalar(@v);
            }
            if($e->can('labels')){
              $e->labels(\@l) if scalar(@v);
            }
            if($e->can('data')){
              $e->data(\@d) if scalar(@d);
            }else{
              $e->data([]);
            }
            if($e->can('metadataval')){
                  $e->metadatalabel(\@ml)  if scalar(@ml);
                  $e->metadataval(\@mv)  if scalar(@mv);
            }

        }else{
          if(ref($e->attrs) ne 'ARRAY'){
            $e->val($d->{$e->attrs->name}) if $d->{$e->attrs->name} ne ''; # ne vs true for 0
            $e->default($d->{$e->attrs->name}) if $d->{$e->attrs->name} ne '';  # ne vs true for 0
          }
          if($e->can('data') && ref($e->data) eq 'ARRAY'){
                my (%d);
                foreach my $dk (@{ $e->data }){
                  $d{$dk} = $d->{ $dk };
                }

                $e->data(\%d);
          }else{
            $e->mk_accessors('data');
            $e->data({});
          }
# show $e, $d if $e->attrs->name eq 'permissions';
        }
             


      }

    # show $c->{_forms}->{$f};  
      return ($c->{_forms}->{$f},$c->{_buttongroup}->{$f});
    } );


    $self->helper(dtsearch => sub {

        my $c = shift;
        my $args = shift;
show $args;        
        my $cols = $args->{columns};
        show $cols;
        my $p = $args->{params};
        my $defer = $args->{defer} || 0;
        my $prefetch = $args->{prefetch};
        my $join = $args->{join};
        my @cols;



#        my $order_by = $p->{ 'columns[' . $p->{'order[0][column]'} . '][data]'  } ? $p->{ 'columns[' . $p->{'order[0][column]'} . '][data]' } : $args->{order_by};
       my $order_by = $p->{ 'columns[' . $p->{'order[0][column]'} . '][data]'  } ? $p->{ 'columns[' . $p->{'order[0][column]'} . '][data]' } : $args->{order_by};
        show $order_by;
	if(ref($order_by) eq 'ARRAY'){
		$order_by = $order_by->[0];
	}
        if($order_by !~ /\./){
          $order_by = 'me.' . $order_by;
        }

        my $sort = $p->{'order[0][dir]'} || $args->{sort};
        my $rsearch = undef;
        my $search = $p->{'search[value]'};
        my $draw = $p->{draw};
        my $length = $p->{length} || 100;
        my $page = ($p->{start} / $length) + 1;

        if($p->{ssearch}){
          my $json = JSON->new->allow_nonref;
          if(ref($p->{ssearch}) =~ /HASH|ARRAY/){
            $rsearch = $p->{ssearch};
          }else{
            my $jobj = $json->decode( $p->{ssearch} );
            $rsearch = $jobj;
          }
        }elsif($p->{asearch}){
show "ASEARCH";
          foreach my $c (keys %$p){
            # this is sloppy

            next if $p->{$c} eq "" || $c eq 'asearch' || $c =~ /\[/ || $c eq 'export' || $c eq 'start' || $c eq 'draw' || $c eq 'length' || $c eq '_' || $c eq 'fuzzy' || $c eq 'boolor' || $c eq 'csv' || $c eq 'csv_seperator';

            if($c =~ /\./){
              if($p->{$c} =~ /^\d+$/  && !$p->{fuzzy}){
                $rsearch->{$c} = $p->{$c};
              }else{
                $rsearch->{$c} = {'like', '%' . $p->{$c} . '%'};
              }
            }else{
              if($p->{$c} =~ /^\d+$/  && !$p->{fuzzy}){
                $rsearch->{'me.' . $c} = $p->{$c};
              }else{
                $rsearch->{'me.' . $c} = {'like', '%' . $p->{$c} . '%'};
              }
            }
          }

         $rsearch = {'-or' => $rsearch} if $rsearch && $p->{boolor} == 1;

          my %rvals;
          # "columns[2][search][value]"
          foreach my $k (keys %$p){
            if($k =~ /columns\[(\d+)\]\[data\]/){
              $cols[$1] = $p->{$k};
            }
          }
          foreach my $k (keys %$p){     
            if($k =~ /columns\[(\d+)\]\[search\]\[value\]/){
              $rvals{$cols[$1]} = $p->{$k};
            }
          }
          
          foreach my $c (keys %rvals){           
            if($c =~ /\./ && $rvals{$c} ne ""){
              $rsearch->{$c} = {'like', '%' . $rvals{$c} . '%'};
            }elsif($rvals{$c} ne ""){
              $rsearch->{'me.' . $c} = {'like', '%' . $rvals{$c} . '%'};
            }
          }


        }elsif($search){

          foreach my $c (@$cols){
            if($c =~ /\./){
              $rsearch->{$c} = {'like', '%' . $search . '%'};
            }else{
              $rsearch->{'me.' . $c} = {'like', '%' . $search . '%'};
            }
          }
          $rsearch = {'-or' => $rsearch} if $rsearch;


        }else{

          my %rvals;
          # "columns[2][search][value]"
          foreach my $k (keys %$p){
            if($k =~ /columns\[(\d+)\]\[data\]/){
              $cols[$1] = $p->{$k};
            }
          }
          foreach my $k (keys %$p){     
            if($k =~ /columns\[(\d+)\]\[search\]\[value\]/){
              $rvals{$cols[$1]} = $p->{$k};
            }
          }
          foreach my $c (keys %rvals){

            if($c =~ /\./ && $rvals{$c} ne ""){
              if(ref($rvals{$c}) eq '' && $c !~ /.*id$/i){
                $rsearch->{$c} = {'like', '%' . $rvals{$c} . '%'};
              }else{
                 $rsearch->{$c} = $rvals{$c};
              }
            }elsif($rvals{$c} ne ""){
              if(ref($rvals{$c}) eq ''  && $c !~ /.*id$/i){
                $rsearch->{'me.' . $c} = {'like', '%' . $rvals{$c} . '%'};
              }else{
                 $rsearch->{'me.' .$c} = $rvals{$c};
              }              
            }
          }

        }

        my $total = $c->db->resultset($args->{table})->search(undef,{prefetch=>$prefetch,group_by=>$args->{group_by}, join => $args->{join},having => $args->{having},                '+select' => $args->{select},
                '+as' => $args->{as},})->count;
        my $count = $c->db->resultset($args->{table})->search($rsearch,{prefetch=>$prefetch,group_by=>$args->{group_by},join => $args->{join}, having => $args->{having},                 '+select' => $args->{select},
                '+as' => $args->{as},})->count;

        my $rparams =  {
                order_by => { '-' . $sort => $order_by },  
                result_class=>'DBIx::Class::ResultClass::HashRefInflator',
                group_by => $args->{group_by},
                prefetch => $args->{prefetch},
                join => $args->{join},
                columns => $args->{columns},
                having => $args->{having},
                '+columns' => $args->{ecolumns},
                # collapse => 1,
                '+select' => $args->{select},
                '+as' => $args->{as},
        };
show $rparams;
        unless($p->{export}){
          $rparams->{rows} = $length;
          $rparams->{page} = $page;
        }else{
          # $rparams->{rows} = 10;
        }
show $rsearch;

        my @c;
        my @rsearch;
        @rsearch = keys %$rsearch if ref($rsearch) eq 'HASH';
        if($p->{export} || ($defer && !scalar(@rsearch))){
          $count = 0;
        }else{
          @c = $c->db->resultset($args->{table})->search($rsearch,$rparams); 
        }
# show @c;        
        if($p->{export}){
          $rparams->{result_class} = undef;
#          $rparams->{page} = 0;
#          $rparams->{rows} = 100;
          my $rs = $c->db->resultset($args->{table})->search($rsearch,$rparams);
          my $fdir =  getcwd() . '/public/files/';
          my $fdir = '/tmp/';

          if($p->{csv}){
              my $filename = $args->{filename} ? $args->{filename} : $args->{table} . '.' . time();
              $filename .= $args->{filename} ?  "" : $args->{ext} ? '.' . $args->{ext} : '.txt';
              my $filepath = $fdir . $filename;
              my ( $fh, $ofilename ) = $c->export_csv($rs,filename => $filepath, trim => $args->{trim}, columns => $args->{excolumns} || $args->{columns}, sep_char => $args->{sep_char} || "\t", exportrowcb => $args->{exportrowcb});
              $c->render_file(
                      'filepath' => $filepath,
                      'format' => 'csv',                 
                      # will change Content-Type "application/x-download" to "application/pdf"
                      'content_disposition' => 'attachment',   
                      # will change Content-Disposition from "attachment" to "inline"  
              );  
               

          # return $c->redirect_to('/files/' . $filename);
          # $c->res->code(200);
          # $c->res->headers->content_type('application/x-download');
          # $c->res->headers->content_disposition('attachment; filename=' . $filename);
          # $c->res->headers->content_length((stat $filepath)[7]);
          # use File::Slurp;
          # show $filepath;
          # my $body = read_file($filepath );
          # show $body;
          # $c->res->body($body);
          # $c->render(data => $body);
          return 1;

#return $c->reply->static($filepath);
  # return $c->res->to_string; 


          }else{


              my $filename = $args->{filename} ? $args->{filename} : $args->{table} . '.' . time() . '.xls';
              my $filepath = $fdir . $filename;
              # @c = $c->db->resultset($args->{table})->search($rsearch,$rparams); 
              my ( $fh, $ofilename ) = $c->export($rs, headers => $args->{exheader}, filename => $filepath, columns => $args->{excolumns} || $args->{columns});

              my $dfilepath = getcwd() . '/public/files/' . $filename;
              move $filepath, $dfilepath;
              $c->res->headers->location('/files/' . $filename);
              $c->rendered(302);
              return 1;

              # my $nfilepath = $fdir . 'X' . $filename;
              # copy $filepath, $nfilepath;
              # show $nfilepath;
              # $c->render_file(
              #         'filepath' => $filepath,
              #         'format' => 'xls',                 
              #         # will change Content-Type "application/x-download" to "application/pdf"
              #         'content_disposition' => 'attachment',   
              #         # will change Content-Disposition from "attachment" to "inline"  
              # );  
# $c->res->headers->cache_control('must-revalidate, post-check=0, pre-check=0, max-age=0');
# $c->res->headers->content_encoding('binary');
# $c->res->headers->expires(0);
# # $c->res->headers->accept_ranges('bytes');
# $c->res->headers->content_type('application/vnd.ms-excel');
# $c->res->headers->content_disposition('attachment; filename=' . $filename);
# # $c->res->headers->server('Apache');
# my $asset = Mojo::Asset::File->new( path => $filepath );
# show $asset;
# $c->res->content->asset($asset);
# $c->rendered(200);
# show $c->res;

              return  1;
          # return $c->redirect_to('/files/' . $filename);

          # $c->res->code(200);
          # my $size = (stat $filepath)[7];
          # $c->res->headers->content_type('application/x-download');
          # $c->res->headers->content_disposition('attachment; filename=' . $filename);
          # $c->res->headers->content_length();

          # use File::Slurp;
          # show $filepath;
          # $/ = undef;
          # my $body = read_file($filepath,  binmode => ':raw' );
          # show $body;
          # write_file('/tmp/test.xls',{binmode => ':raw'},$body);
          # $c->res->body($body);
          # return $c->render(data => $body);
          # return 1;

          }
          # @c = map { 
          #   my $h = flatten($_); 
          #   my @v = @$h{ @$cols };
          #   my $v = \@v; 
          # } @c;

        }

        my $jobj = {
          "draw" => $draw,
          "recordsTotal" => $total,
          "recordsFiltered" => $count,
          "data" => \@c,
          "header" => $cols
        };

        return $jobj;

  });


  $self->helper(gpslatlon => sub{
      my $c = shift;
      my $src = shift;
      my $dst = shift;


      if($dst){
          my $url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=$src&destinations=$dst&key=AIzaSyCP1YIwEFWU7WDiNbUdo4MPbOZEJcQtN9I";
          my $ua = LWP::UserAgent::JSON->new;
          my $req = HTTP::Request::JSON->new(GET => $url);
          my $response = $ua->request($req);
          if($response->can('json_content')){
            if($response->json_content->{rows}->[0]->{elements}->[0]->{status} eq 'NOT_FOUND'  || $response->json_content->{status} eq 'UNKNOWN_ERROR' || $response->json_content->{status} eq 'INVALID_REQUEST'){
              $response->json_content->{error_message};
              show $src, $dst, $response->json_content;
            }

            my $r = $response->json_content->{"rows"}->[0]->{"elements"}->[0]->{"distance"}->{"value"};
            if($r){
              my $d = sprintf("%.2f", $r/1609.34);
              return $d;
            }
            return 0;
          }
          return 0;
      }else{
          my $url = "https://maps.googleapis.com/maps/api/geocode/json?address=$src&key=AIzaSyCP1YIwEFWU7WDiNbUdo4MPbOZEJcQtN9I";
          my $ua = LWP::UserAgent::JSON->new;
          my $req = HTTP::Request::JSON->new(GET => $url);
          my $response = $ua->request($req);

          my ($lat,$lon) = (0,0);
          # show $response->json_content;
          if($response->can('json_content')){

            if($response->json_content->{status} eq 'ZERO_RESULTS' || $response->json_content->{status} eq 'UNKNOWN_ERROR'){
              show $src, $response->json_content;
            }

            $lat = $response->json_content->{"results"}->[0]->{"geometry"}->{"location"}->{"lat"};
            $lon = $response->json_content->{"results"}->[0]->{"geometry"}->{"location"}->{"lng"};
            return ($lat,$lon);
          }
          return (0,0);
      }
      

  });

  $self->helper(export => sub{
      return ExcelExport->export_excel(@_);
  });
  $self->helper(export_hr => sub{
      return ExcelExport->export_excel_hr(@_);
  });    
  $self->helper(export_csv => sub{
      return ExcelExport->export_csv(@_);
  });  
  $self->helper(dtconvert => sub{
    my($self,$ut) = (@_);
    return DateTime->from_epoch( epoch => $ut )->datetime();

  });

  $self->helper(form => sub {
  	my($self,$fd) = (@_);
    my $f = $self->app->objectify($fd);
  	return $f;
  });

  $self->helper(validate => sub {
    my($self,$c,$v,$j) = (@_);

    my $errors;
    foreach my $k (keys %$v){
      my ($p,$m) = $v->{$k}->($j->{$k});
      $errors->{$k} = $m unless $p;
    }
    return $errors;
  });

  my $config = $self->plugin('Config',{file=> getcwd() . '/clmapp.conf'});
  my $mailconf = $config->{mailconf};
  $self->plugin('mail' => $mailconf);

  #$self->log( Mojo::Log->new( path => getcwd() . '/logs/clmapp.log', level => 'debug' ) );

  # $self->config(hypnotoad => {listen => ['http://*:3000']});


  $self->load_defaults;
  $self->types->type(xls => 'application/vnd.ms-excel', csv => 'application/download');

  # Router
  my $r = $self->routes;
  $self->sessions->default_expiration(14400); # 4 hours
  $self->secrets(['<JgP$)]B-n!5nTsZbD3</5X']);

  $r->post('/api/user/login')->to(controller=>'User', action => 'auth');
  $r->get('/login')->to(controller=>'User', action => 'login');
  $r->get('/logout')->to(controller=>'User', action => 'logout');
  $r->any('/api/session')->to(controller=>'Root', action=>'sessionjson');
  my $a = $r->under('/')->to(controller=>'User', action => 'auth');
  $a->get('/dashboard')->to('root#dashboard');
  $a->get('/api/gps')->to('root#gps');
  $a->get('/')->to('root#dashboard');

  $a->get('/user')->to('user#index');
  $a->get('/api/user')->to('user#list');
  $a->get('/api/user/:user_id')->to(controller=>'User', action => 'read');
  $a->post('/api/user')->to(controller=>'User', action => 'create');
  $a->put('/api/user/:user_id')->to(controller=>'User', action => 'update');
  $a->delete('/api/user/:user_id')->to(controller=>'User', action => 'delete');

  $a->get('/customer')->to('customer#index');
  $a->get('/api/customer')->to('customer#list');
  $a->get('/api/customer/:customerid')->to(controller=>'Customer', action => 'read');
  $a->get('/api/customer/search')->to(controller=>'Customer', action => 'search');
  $a->post('/api/customer')->to(controller=>'Customer', action => 'create');
  $a->put('/api/customer/:customerid')->to(controller=>'Customer', action => 'update');
  $a->delete('/api/customer/:customerid')->to(controller=>'Customer', action => 'delete');
  $a->get('/customer/report/missing')->to(controller=>'Customer', action => 'report');
  $a->get('/customer/report/orderguide')->to(controller=>'Customer', action => 'report');
  $a->get('/customer/report/gps')->to(controller=>'Customer', action => 'report');
  $a->get('/api/customer/report/missing')->to(controller=>'Customer', action => 'report_missing');
  $a->get('/api/customer/report/orderguide')->to(controller=>'Customer', action => 'report_orderguide');
  $a->get('/api/customer/report/gps')->to(controller=>'Customer', action => 'report_gps');
  $a->get('/api/customer/report/export_itn')->to(controller=>'Customer', action => 'export_itn');
  $a->get('/api/customer/report/export_itn_bp')->to(controller=>'Customer', action => 'export_itn_bp');
  # no auth, probably OK
  $r->get('/api/customer/report/export_gfs')->to(controller=>'Customer', action => 'export_gfs');
  $r->get('/api/customer/report/export_gps')->to(controller=>'Customer', action => 'export_gps');
  $a->get('/api/customer/report/export_bpunitmaster')->to(controller=>'Customer', action => 'export_bpunitmaster');
  $a->get('/api/customer/report/export_bpunitloginent')->to(controller=>'Customer', action => 'export_bpunitloginent');
  $a->get('/api/customer/report/export_bpthirdpartyacount')->to(controller=>'Customer', action => 'export_bpthirdpartyacount');
  $a->get('/api/customer/report/export_bphierarchymaster')->to(controller=>'Customer', action => 'export_bphierarchymaster');    

  $a->get('/dmavp')->to('dmavp#index');
  $a->get('/api/dmavp')->to('dmavp#list');
  $a->get('/api/dmavp/:dmavpid')->to(controller=>'dmavp', action => 'read');
  $a->post('/api/dmavp')->to(controller=>'dmavp', action => 'create');
  $a->put('/api/dmavp/:dmavpid')->to(controller=>'dmavp', action => 'update');
  $a->delete('/api/dmavp/:dmavpid')->to(controller=>'dmavp', action => 'delete');

  $a->get('/dmaprogrammanager')->to(controller=>'DmaprogramManager',action => 'index');
  $a->get('/api/dmaprogrammanager')->to(controller=>'DmaprogramManager', action => 'list');
  $a->get('/api/dmaprogrammanager/:dmaprogrammanagerid')->to(controller=>'DmaprogramManager', action => 'read');
  $a->post('/api/dmaprogrammanager')->to(controller=>'DmaprogramManager', action => 'create');
  $a->put('/api/dmaprogrammanager/:dmaprogrammanagerid')->to(controller=>'DmaprogramManager', action => 'update');
  $a->delete('/api/dmaprogrammanager/:dmaprogrammanagerid')->to(controller=>'DmaprogramManager', action => 'delete');

  $a->get('/distributorcompany')->to(controller=>'DistributorCompany',action => 'index');
  $a->get('/api/distributorcompany')->to(controller=>'DistributorCompany', action => 'list');
  $a->get('/api/distributorcompany/:distributorcompanyid')->to(controller=>'DistributorCompany', action => 'read');
  $a->post('/api/distributorcompany')->to(controller=>'DistributorCompany', action => 'create');
  $a->put('/api/distributorcompany/:distributorcompanyid')->to(controller=>'DistributorCompany', action => 'update');
  $a->delete('/api/distributorcompany/:distributorcompanyid')->to(controller=>'DistributorCompany', action => 'delete');
  $a->get('/distributorcompany/report/address')->to(controller=>'DistributorCompany', action => 'report');
  $a->get('/api/distributorcompany/report/address')->to(controller=>'DistributorCompany', action => 'report_address');



  $a->get('/distributorwarehouse')->to(controller=>'DistributorWarehouse',action => 'index');
  $a->get('/api/distributorwarehouse')->to(controller=>'DistributorWarehouse', action => 'list');
  $a->get('/api/distributorwarehouse/:distributorwarehouseid')->to(controller=>'DistributorWarehouse', action => 'read');
  $a->post('/api/distributorwarehouse')->to(controller=>'DistributorWarehouse', action => 'create');
  $a->put('/api/distributorwarehouse/:distributorwarehouseid')->to(controller=>'DistributorWarehouse', action => 'update');
  $a->delete('/api/distributorwarehouse/:distributorwarehouseid')->to(controller=>'DistributorWarehouse', action => 'delete');
  $a->get('/distributorwarehouse/report/all')->to(controller=>'DistributorWarehouse', action => 'report');    
  $a->get('/api/distributorwarehouse/report/all')->to(controller=>'DistributorWarehouse', action => 'report_all'); 
  $a->get('/distributorwarehouse/report/gps')->to(controller=>'DistributorWarehouse', action => 'report');
  $a->get('/api/distributorwarehouse/report/gps')->to(controller=>'DistributorWarehouse', action => 'report_gps');



  $a->get('/chaingroup')->to(controller=>'ChainGroup',action => 'index');
  $a->get('/api/chaingroup')->to(controller=>'ChainGroup', action => 'list');
  $a->get('/api/chaingroup/:chaingroupid')->to(controller=>'ChainGroup', action => 'read');
  $a->post('/api/chaingroup')->to(controller=>'ChainGroup', action => 'create');
  $a->put('/api/chaingroup/:chaingroupid')->to(controller=>'ChainGroup', action => 'update');
  $a->delete('/api/chaingroup/:chaingroupid')->to(controller=>'ChainGroup', action => 'delete');    

  $a->get('/chainconcept')->to(controller=>'ChainConcept',action => 'index');
  $a->get('/api/chainconcept')->to(controller=>'ChainConcept', action => 'list');
  $a->get('/api/chainconcept/:chainconceptid')->to(controller=>'ChainConcept', action => 'read');
  $a->post('/api/chainconcept')->to(controller=>'ChainConcept', action => 'create');
  $a->put('/api/chainconcept/:chainconceptid')->to(controller=>'ChainConcept', action => 'update');
  $a->delete('/api/chainconcept/:chainconceptid')->to(controller=>'ChainConcept', action => 'delete');
  $a->get('/api/chainconcept/report/export_threshold')->to(controller=>'ChainConcept', action => 'export_threshold');
  
  $a->get('/api/chainunit/bulk_deactivate')->to(controller=>'ChainUnit',action => 'bulk_deactivate');
  $a->get('/chainunit')->to(controller=>'ChainUnit',action => 'index');
  $a->get('/api/chainunit')->to(controller=>'ChainUnit', action => 'list');
  $a->get('/api/chainunit/:chainunitid')->to(controller=>'ChainUnit', action => 'read');
  $a->post('/api/chainunit')->to(controller=>'ChainUnit', action => 'create');
  $a->put('/api/chainunit/:chainunitid')->to(controller=>'ChainUnit', action => 'update');
  $a->delete('/api/chainunit/:chainunitid')->to(controller=>'ChainUnit', action => 'delete');

  $a->get('/chainunit/report/orphaned')->to(controller=>'ChainUnit', action => 'report');
  $a->get('/chainunit/report/unassigned')->to(controller=>'ChainUnit', action => 'report');
  $a->get('/api/chainunit/report/orphaned')->to(controller=>'ChainUnit', action => 'report_orphaned');
  $a->get('/api/chainunit/report/unassigned')->to(controller=>'ChainUnit', action => 'report_unassigned');


  $a->get('/backofficesystem')->to(controller=>'BackOfficeSystem',action => 'index');
  $a->get('/api/backofficesystem')->to(controller=>'BackOfficeSystem', action => 'list');
  $a->get('/api/backofficesystem/:systemid')->to(controller=>'BackOfficeSystem', action => 'read');
  $a->get('/api/backofficesystem/concept/:chainconceptid')->to(controller=>'BackOfficeSystem', action => 'concept');  
  $a->post('/api/backofficesystem')->to(controller=>'BackOfficeSystem', action => 'create');
  $a->put('/api/backofficesystem/:systemid')->to(controller=>'BackOfficeSystem', action => 'update');
  $a->delete('/api/backofficesystem/:systemid')->to(controller=>'BackOfficeSystem', action => 'delete');

  $a->get('/country')->to(controller=>'country',action => 'index');
  $a->get('/api/country')->to(controller=>'country', action => 'list');
  $a->get('/api/country/:countrycode')->to(controller=>'country', action => 'read');
  $a->post('/api/country')->to(controller=>'country', action => 'create');
  $a->put('/api/country/:countrycode')->to(controller=>'country', action => 'update');
  $a->delete('/api/country/:countrycode')->to(controller=>'country', action => 'delete');  

  # $self->max_request_size(1073741824);
  $a->get('/import')->to(controller=>'Import',action => 'index');
  $a->post('/import/excel')->to(controller=>'Import',action => 'excel');
  $a->post('/import/itn')->to(controller=>'Import',action => 'itn');
  $a->post('/api/import/itn')->to(controller=>'Import',action => 'itn2');

  $a->any('/api/datatable/view/:table')->to(controller=>'DataTable', action => 'list');
  $a->get('/api/datatable/view/:table/:key')->to(controller=>'DataTable', action => 'read');
  $a->delete('/api/datatable/view/:table/:key')->to(controller=>'DataTable', action => 'delete');

  $a->get('/bpmigration')->to(controller=>'Bpmigration', action => 'index');
  $a->get('/api/bpmigration')->to(controller=>'Bpmigration', action => 'list');
  $a->any('/api/bpmigration/check')->to(controller=>'Bpmigration', action => 'check');
  $a->any('/api/bpmigration/migrate/#bpmigrationid')->to(controller=>'Bpmigration', action => 'migrate');
  $a->any('/api/bpmigration/delete/#bpmigrationid')->to(controller=>'Bpmigration', action => 'markdeleted');
  $a->post('/api/bpmigration/list')->to(controller=>'Bpmigration', action => 'list');
  $a->get('/api/bpmigration/#bpmigrationid')->to(controller=>'Bpmigration', action => 'read');
  $a->post('/api/bpmigration')->to(controller=>'Bpmigration', action => 'create');
  $a->put('/api/bpmigration/#bpmigrationid')->to(controller=>'Bpmigration', action => 'update');
  $a->delete('/api/bpmigration/#bpmigrationid')->to(controller=>'Bpmigration', action => 'delete');

  $a->get('/emailnotification')->to(controller=>'EmailNotification', action => 'index');
  $a->get('/api/emailnotification')->to(controller=>'EmailNotification', action => 'list');
  # $a->any('/api/emailnotification/check')->to(controller=>'EmailNotification', action => 'check');
  # $a->any('/api/emailnotification/migrate/#emailnotificationid')->to(controller=>'EmailNotification', action => 'migrate');
  $a->post('/api/emailnotification/list')->to(controller=>'EmailNotification', action => 'list');
  $a->get('/api/emailnotification/#emailnotificationid')->to(controller=>'EmailNotification', action => 'read');
  $a->post('/api/emailnotification')->to(controller=>'EmailNotification', action => 'create');
  $a->put('/api/emailnotification/#emailnotificationid')->to(controller=>'EmailNotification', action => 'update');
  $a->delete('/api/emailnotification/#emailnotificationid')->to(controller=>'EmailNotification', action => 'delete');

  $a->get('/opf')->to(controller=>'Root', action => 'opf');
  $a->get('/opf/*file')->to(controller=>'Root', action => 'opfdownload');
  $a->get('/opfftp/*file')->to(controller=>'Root', action => 'opfftp');
  $a->get('/opfftpupload/*file')->to(controller=>'Root', action => 'opfftpupload');

# create
  # $a->post('/api/datatable/view')->to(controller=>'DataTable', action => 'create');
  show %ENV;

}

1;

