package App::POS::Check;

use strict;
use warnings;
use FindBin qw( $Bin );
use File::Path qw( mkpath );
use File::Slurp qw( read_dir read_file write_file );
use File::Copy qw( copy move );
use Data::Dumper;
use File::Remove qw( remove );
use POSIX qw( strftime );
use Fcntl ':flock';

use base qw( App::Class );

sub init {
  my $self = shift;
  my %a = ( file => undef, lazy => undef, @_ );

  $self->debug("init");

  die "Missing 'file' parameter..." unless defined $a{file};

  my $to_print = 1;
  $to_print = 0 if -e $a{file}.".print.0";
  $self->{to_print} = $to_print;

  if ($a{file} =~ /\.close/) {
    my( $path, $area, $table ) = $a{file} =~ /^(.*?)\/areas\/(\d+)\/(.*?)\.close/;
    $table =~ s/\.toprint//g;

    $self->{path} = $path;
    $self->{table_number} = $table;
    $self->{area} = $area;
  }
  elsif ($a{file} =~ /^(.*?)\/areas\/(\d+)\/(\d+)\.\d+\.hold\.check$/) {
    # /opt/pos/server/data/areas/1/15.0.hold.check
    my $path = $1;
    my $area = $2;
    my $table = $3;
    #my( $path, $area, $table ) = $a{file} =~ /^(.*?)\/areas\/(\d+)\/(.*?)$/;
    $table =~ s/\.toprint//g;

    $self->{path} = $path;
    $self->{table_number} = $table;
    $self->{area} = $area;
  }
  else {
    #'file' => '/opt/pos/server/data/areas/1/14'
    my( $path, $area, $table ) = $a{file} =~ /^(.*?)\/areas\/(\d+)\/(.*?)$/;
    $table =~ s/\.toprint//g;

    $self->{path} = $path;
    $self->{table_number} = $table;
    $self->{area} = $area;
  }

  # inititalize the check data as being undefined
  $self->{data} = undef;

  $self->{value} = 0;

  if (! defined $a{lazy}) {
    # load the check
    $self->load();

    # if we've a .total file, read it
    if (-e $a{file}.".total") {
      local $/ = undef;
      open(F, "< ".$a{file}.".total");
      my $cnt = <F>;
      $cnt =~ s/\n//g;
      $self->{value} = $cnt;
      close(F);
    }
  }
}

sub business_date {
  my $self = shift;

  if (! defined $self->{data}) {
    # load the check
    $self->load();
  }

  my $d = $self->{data};

  if (scalar @{ $d->{header} }) {
#    #201201170836080.636672134547236
#    if ($d->{header}->[23] =~ /^\d+\.\d+$/) {
#      my( $y, $m, $d ) = $d->{header}->[23] =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
#      return "$y-$m-$d";
#    }
#    else {
      return $d->{header}->[23];
#    }
  } else {
    return &strftime("%Y-%m-%d", localtime),
  }
}

sub mark_done {
  my $self = shift;
  
  my $f = $self->file_done();

  open(F, "> $f");
  print F "1\n";
  close(F);
}

sub file_done {
  my $self = shift;
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number() . ".done";
}

sub file_has_unholded_products {
  my $self = shift;
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number() . ".unholded";
}

sub file_close {
  my $self = shift;
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number() . ".close";
}

sub file_name {
  my $self = shift;
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number() . ".name";
}

sub file_check {
  my $self = shift;
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number();
}

sub file_hold {
  my $self = shift;
  my $station = 0;
  my $headers = $self->{data}->{header} || [];
  if (scalar @$headers && scalar(@$headers) >= 6) {
    $station = $headers->[5] || 0;
  }
  return $self->path() . "/areas/" . $self->area() . "/" . $self->table_number() . "." . $station . ".hold";
}

sub finalize {
  my $self = shift;
  my $print = shift || 0;
  #13.0.hold
  write_file($self->file_hold(), 1);
  #13.close.print.1
  write_file($self->file_close() . ".print." . $print, 1);
  #13.0.hold.check
  copy($self->file(), $self->file_hold() . ".check");
  #13.close
  move($self->file(), $self->file_close());
}

=pod
generate_empty_header

  if (scalar @{ $d->{header} }) {


-rw-rw-r-- 1 pos  pos     2 Mar 16 19:34 13.0.hold
1   sem \n

-rw-rw-r-- 1 pos  pos   492 Mar 16 19:34 13.0.hold.check
uma copia da conta toda
=cut


sub name {
  my $self = shift;

  my $name_file = $self->{path}."/areas/".$self->{area}."/".$self->{table_number}.".name";

  if (-e $name_file) {
    local $/ = undef;
    open(F, "< ".$name_file);
    my $cnt = <F>;
    chop($cnt);
    close(F);
    return $cnt;
  }
  else {
    #return $self->{table_number};
    return "";
  }
}

sub products_extra_data {
  my $self = shift;

  if (! scalar @_) {
    return $self->{data}->{products_extra_data};
  } else {
    if (scalar @_ == 2) {
      my( $key, $value ) = @_;
      $self->{data}->{products_extra_data}->{$key} = $value;
    } else {
      my $key = shift;
      return $self->{data}->{products_extra_data}->{$key};
    }
  }
}

sub extra_data_update {
  my $self = shift;
  my $ref = shift;
  $self->{data}->{extra_data} = $ref;
}

sub extra_data {
  my $self = shift;

  if (! scalar @_) {
    return $self->{data}->{extra_data};
  } else {
    if (scalar @_ == 2) {
      my( $key, $value ) = @_;
      $self->{data}->{extra_data}->{$key} = $value;
    } else {
      my $key = shift;
      return $self->{data}->{extra_data}->{$key};
    }
  }
}

sub path {
  my $self = shift;
  return $self->{path};
}

sub to_print {
  my $self = shift;
  return $self->{to_print};
}

sub area {
  my $self = shift;
  return $self->{area};
}

sub table_number {
  my $self = shift;
  my $ed = $self->extra_data();

  if (exists $ed->{original_table} && $ed->{original_table}) {
    return $ed->{original_table};
  }
  else {
    return $self->{table_number};
  }
}

# file representing the check
sub file {
  my $self = shift;
  return $self->{file};
}

# check data
sub data {
  my $self = shift;

  if (! defined $self->{data}) {
    $self->{data}->{header} = [];
    $self->{data}->{details} = [];
    $self->{data}->{details_deleted} = [];
  }

  return $self->{data};
}

# set check data
sub set_data {
  my $self = shift;
  my $data = shift;
  $self->{data} = $data;
}

# check value
sub value {
  my $self = shift;
  my $v = $self->{value};
  $v =~ s/\n//g;
  return $v;
}

# check value without discount and vat
sub value_net {
  my $self = shift;

  #print STDERR Dumper($self);
  #return $v;
}

sub delete {
  my $self = shift;
  my $dont_delete_lock = shift;

  #my( $path, $area, $table ) = $a{file} =~ /^(.*?)\/areas\/(\d+)\/(.*?)\.close/;
  #$self->{path} = $path;
  #$self->{table_number} = $table;
  #$self->{area} = $area;

  my $p = $self->file_check();

  &remove($p);

  if (! defined $dont_delete_lock) {
    &remove($p.".*");
  }
  else {
    my $r = int(rand(10000));
    copy( $p.".lock", "/opt/pos/common/tmp/".$$."_".$r.".lock");
    &remove($p.".*");
    move("/opt/pos/common/tmp/".$$."_".$r.".lock", $p.".lock");
  }
}

sub had_bill {
  my $self = shift;
  return -e $self->file().".bill" ? 1 : 0;
}

sub is_locked {
  my $self = shift;
  return -e $self->file().".lock" ? 1 : 0;
}

sub is_holded {
  my $self = shift;
  return -e $self->file().".hold" ? 1 : 0;
}

sub hold {
  my $self = shift;
}

sub save {
  my $self = shift;

  my $d = $self->{data};

  $d->{header} ||= [];
  $d->{details} ||= [];
  $d->{footers} ||= [];
  $d->{details_deleted} ||= [];
  $d->{extra_data} ||= {};
  $d->{products_extra_data} ||= {};

  my $PCI = 0;
  my $Q = 0;
  my $PERCIVA = 0;
  my $PSI = 0;
  my $DESCONTO = 0;
  my $_Total_com_IVA = 0;

  my $cnt = "DETAILS\n";

  my $line_num = 0;

  foreach my $d (@{ $d->{details} }) {
    next unless scalar @$d;
    $d->[11] ||= 0;
    $d->[3] ||= 0;

    # ignore lines with qtty 0
    next if $d->[3] == 0;

    $d->[0] = $line_num;

    $PCI = $d->[4];
    $Q = $d->[3];
    $PERCIVA = $d->[6];

    my $discount_txt = $d->[11] || '';
    $d->[5] = 0; # calculated discount wo vat

    # percent discount
    if ($discount_txt) {
      if ($discount_txt =~ /\%/) {
        $discount_txt =~ s/\%//g;
        $discount_txt = $PCI * ($discount_txt / 100); # valor do desconto sobre o preco unit com iva
        $d->[5] = $discount_txt / (1 + ($PERCIVA / 100));
      } else {
        if ($PERCIVA != 0) {
          $d->[5] = $discount_txt / (1 + ($PERCIVA / 100));
        }
      }
    }

    my $desc_com_iva = 0;

    if ($d->[5]) {
      $desc_com_iva = $d->[5] * (1 + $PERCIVA / 100);
    }

    $_Total_com_IVA += ($PCI - $desc_com_iva) * $Q;

    #$PCI = $d->[4] || 0;
    #$Q = $d->[3] || 1;
    #$PERCIVA = $d->[6] || 0;
    #$PSI = $PCI / (1 + ($PERCIVA / 100));
    #$DESCONTO = $d->[11];
    #$PCI = ($PSI - $DESCONTO) * (1 + $PERCIVA / 100);

    my $line = join("#", @$d);
    $cnt .= $line."\n";

    $line_num++;
  }

  my $discount_total = $d->{header}->[10] || 0;

  if ($discount_total) {
    if ($discount_total =~ /\%/) {
      $discount_total =~ s/\%//g;
      $discount_total = $_Total_com_IVA * ($discount_total / 100); # valor do desconto
      $d->{header}->[9] = $discount_total;
    } else {
      $d->{header}->[9] = $d->{header}->[10];
    }

    $_Total_com_IVA -= $d->{header}->[9];
  }

  #print STDERR "##### _Total_com_IVA: $_Total_com_IVA\n";

  my $cnt2 = "HEADER\n";
  $d->{header}->[19] = $_Total_com_IVA;
  $self->{value} = $_Total_com_IVA;

  for (@{$d->{header}}) {
    $_ = "" unless defined $_;
  }

  $cnt2 .= join("#", @{ $d->{header} }) . "\n";

  $cnt = $cnt2.$cnt;

  if (scalar @{ $d->{footers} }) {
    $cnt .= "FOOTERS\n";
    my $line_num = 0;

    foreach my $d (@{ $d->{footers} }) {
      next unless scalar @$d;
      my $line = join("#", @$d);
      $cnt .= $line."\n";
      $line_num++;
    }
  }

  if (scalar @{ $d->{details_deleted} }) {
    open(F, "> ".$self->file().".deleted");
    foreach my $d (@{ $d->{details_deleted} }) {
      my $line = join("#", @$d);
      print F $line."\n";
    }
    close(F);
  }

  if (scalar keys %{ $d->{extra_data} }) {
    $cnt .= "EXTRA_DATA\n";

    foreach my $k (keys %{ $d->{extra_data} }) {
      $cnt .= "$k=".$d->{extra_data}->{$k}."\n";
    }
  }

  if (scalar keys %{ $d->{products_extra_data} }) {
    $cnt .= "PRODUCTS_EXTRA_DATA\n";

    foreach my $k (keys %{ $d->{products_extra_data} }) {
      $cnt .= "$k=".$d->{products_extra_data}->{$k}."\n";
    }
  }

  $_Total_com_IVA ||= 0;

  $self->_write_with_lock($self->file(), $cnt."\n");
  $self->_write_with_lock($self->file().".total", sprintf("%.2f", $_Total_com_IVA)."\n");

  if ($_Total_com_IVA*1 == 0 && ! scalar @{$d->{details}} && ! scalar @{$d->{details_deleted}}) {
    unlink $self->file().".total";
  }
}

# load check info
sub load {
  my $self = shift;
  $self->debug("load");

  local $/ = "\n";

  my $info = {};

  $info->{extra_data} = {};
  $info->{header} = [];
  $info->{footers} = [];
  $info->{details} = [];
  $info->{details_deleted} = [];
  $info->{extra_data} = {};
  $info->{products_extra_data} = {};

  my $deleted_file = "";
  my $deleted_file1 = $self->{path}."/areas/".$self->{area}."/".$self->{table_number}.".deleted";
  my $deleted_file2 = $self->{path}."/areas/".$self->{area}."/".$self->{table_number}.".close.deleted";

  if (-e $deleted_file1) {
    $deleted_file = $deleted_file1;
  }

  if (! $deleted_file && ! -e $deleted_file1 && -e $deleted_file2) {
    $deleted_file = $deleted_file2;
  }

  if (open(F, "< ".$deleted_file)) {
    while (<F>) {
      chop;
      my @a = split /#/;
      push @{ $info->{details_deleted} }, \@a;
    }
    close(F);
  }

  if (open(F, "< ".$self->file())) {
    my $str = "";
    my $read_header = 0;
    my $read_details = 0;
    my $read_footers = 0;
    my $read_extra_data = 0;
    my $read_products_extra_data = 0;

    while (<F>) {
      chop;

      next unless $_;

      if ($_ eq 'HEADER') {
        $read_header = 1;
        $read_details = 0;
        $read_footers = 0;
        $read_extra_data = 0;
        $read_products_extra_data = 0;
      }
      elsif ($_ eq 'DETAILS') {
        $read_header = 0;
        $read_details = 1;
        $read_footers = 0;
        $read_extra_data = 0;
        $read_products_extra_data = 0;
      }
      elsif ($_ eq 'FOOTERS') {
        $read_header = 0;
        $read_details = 0;
        $read_footers = 1;
        $read_extra_data = 0;
        $read_products_extra_data = 0;
      }
      elsif ($_ eq 'EXTRA_DATA') {
        $read_header = 0;
        $read_details = 0;
        $read_footers = 0;
        $read_extra_data = 1;
        $read_products_extra_data = 0;
      }
      elsif ($_ eq 'PRODUCTS_EXTRA_DATA') {
        $read_header = 0;
        $read_details = 0;
        $read_footers = 0;
        $read_extra_data = 0;
        $read_products_extra_data = 1;
      }
      elsif ($read_header) {
        my @a = split /#/;
        $info->{header} = \@a;
        $read_header = 0;
      }
      elsif ($read_details) {
        my @a = split /#/;
        push @{ $info->{details} }, \@a;
      }
      elsif ($read_footers) {
        my @a = split /#/;
        push @{ $info->{footers} }, \@a;
      }
      elsif ($read_extra_data) {
        my @a = split /=/;

        if (scalar @a == 2) {
          $info->{extra_data}->{$a[0]} = $a[1];
        }
      }
      elsif ($read_products_extra_data) {
        my @a = split /=/;

        if (scalar @a == 2) {
          $info->{products_extra_data}->{$a[0]} = $a[1];
        }
      }
    }

    $self->{data} = $info;

    close(F);

    $self->{value} = $info->{header}->[19];
  }
}

sub generate_empty_header {
  my $self = shift;
  my( $date, $business_date, $clerk_id, $area_id, $station ) = @_;

  $station ||= 0;

  my $str = &strftime("%Y%m%d%H%M%S", localtime) . rand();
  $str =~ s/\.//g;

  return (
    $date, $date, $clerk_id, $clerk_id, $station, $station, $area_id, $area_id,
    5, 0, "", 0, "", "", 0, 1, 0, 0, "", 0, "", 0, 0, $business_date,
    $str,
  );
}

sub _write_with_lock {
  my $self = shift;
  my( $file, $content ) = @_;

  open(F, '>', $file) or die "Could not open '$file' - $!";

  # Get exclusive lock (will block until it does)
  flock(F, LOCK_EX) or die "Could not lock '$file' - $!";

  print F $content;

  close(F) or die "Could not write '$file' - $!";
}

1;

