#!/usr/bin/perl
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (c) Rainer Gümpelein, TeilRad GmbH
#
#Examples
#./src/scripts/Ilockit_cloud.pl shareedms-operator get_events 95
#
#./src/scripts/Ilockit_cloud.pl shareedms-operator get_positions
#
#Ilockit GPS cloud
#
#4. Get a list of positions
#fetch_ >> https://tracking.ilockit.bike/api/positions?from=2021-05-31T07:44:10Z&to=2021-06-06T07:44:10Z&deviceId=4272

#5. Get a list of Events
#fetch_ >> https://tracking.ilockit.bike/api/reports/events?from=2021-05-31T07:44:10Z&to=2021-06-06T07:44:10Z&deviceId=4272

use vars qw($syshost);

BEGIN {
  $syshost = $ARGV[0] || die;
}

use lib "/var/www/copri-bike/$syshost/src";
use strict;
use warnings;
use POSIX;
use JSON;
use LWP::UserAgent;
use DateTime;
use Time::Piece;

use Mod::DBtank;
use Data::Dumper;

my $dbt = new DBtank;
my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime;

my $api_file = "/var/www/copri4/shareeconf/apikeys.cfg";
my $aconf = Config::General->new($api_file);
my %apikeyconf = $aconf->getall;
#print "---> " . $apikeyconf{Ilockitcloud}->{username} . "\n";

my $ua = LWP::UserAgent->new;
$ua->agent("sharee APIclient");
$ua->credentials( 'tracking.ilockit.bike:443', 'api', "$apikeyconf{Ilockitcloud}->{username}", "$apikeyconf{Ilockitcloud}->{passwd}");

my $json = JSON->new->allow_nonref;
my $owner = 183;

my $todo = $ARGV[1];
my $groupId = $ARGV[2] || "";
my $deviceId = $ARGV[3] || "";

open(FILE,">>$dbt->{copri_conf}->{logdir}/Ilockit_cloud.log");
print FILE "\n\n*** $now_dt\n";

 #2022-11-08 looping and rest changed to groupId and limit (max 10000)
 #get Ilockit events by groupId
 my $endpoint = "https://tracking.ilockit.bike/api/reports/events";
 my $rest = "groupId=$groupId\&limit=100"; 
 my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest);
 my $response_in = {};
 $response_in = decode_json($ret_json);
 print FILE "Ilockit $todo response_in:" . Dumper($response_in);

#main
#loop operators DB
while (my ($key, $op_name) = each %{ $dbt->{operator} }) {
 if($op_name->{database}->{dbname} && $op_name->{hwtype} ne "sigo"){
   print FILE "\nON----------$op_name->{database}->{dbname}---$now_dt | $todo\n";
   my $rows = 0;

   my $sharee_operator = $op_name->{database}->{dbname};
   my $dbh = "";
   $dbh = $dbt->dbconnect_extern($sharee_operator);

   #per cronjob once a day to get and update content with cloud device id
   #./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_devices
   &get_devices($dbh,$op_name) if($todo eq "get_devices");

   #./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_events 95
   if($todo eq "get_events"){
     &get_events($dbh,$op_name,$response_in);
     &get_positions($dbh,$op_name);
   }
   #./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_positions 6572
   #&get_positions($dbh,$op_name->{oprefix}) if($todo eq "get_positions");
 }
}


#my $endpoint = "https://tracking.ilockit.bike/api/commands";
#utc to localtime
sub localizedtime {
 my $date = shift;

 $date =~ s/\..*$//;
 my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S");
 print FILE "localizedtime GMT alias Zulu: " . $time->datetime . "\n";#GMT alias Zulu
 $time = localtime($time->epoch);#epoch
 print FILE "localizedtime localized date time: " . $time->datetime . "\n";#localized date time
 
 return $time->datetime;
}
#print localizedtime("2021-06-11T11:58:09.000+0000") . " example\n";

#localtime to utc
#my $now = strftime "%Y-%m-%dT%H:%M:%S", localtime;
#utctime($now);
sub utctime {
 my $date = shift;
 my $latency = shift || 0;

 $date =~ s/\..*$//;
 $date =~ s/\+\d+$//;
 print FILE "requested datetime: " . $date . "\n";

 my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S");
 print FILE "localtime: " . $time->datetime . "\n";#localtime
 my $utc_epoch = $time->epoch;
 #
 #only -1 hour, because of deviceTime and serverTime differs
 #'deviceTime' => '2021-10-14T08:19:35.000+0000',
 #'serverTime' => '2021-10-14T07:19:37.000+0000',

 $utc_epoch -= 2*60*60;# -2 std (Sommerzeit)
 #$utc_epoch -= 1*60*60;# -1 std (Winterzeit)

 $utc_epoch += $latency;
 $time = gmtime($utc_epoch);#epoch
 print FILE "utctime: " . $time->datetime . "\n";#utc zulu date time
 #
 return $time->datetime;
}


#get all device localy
sub get_devicesONcontent_all {
 my $dbh = shift;
 my $serialnr = shift || "";
 my $pref = {
        table           => "content",
        fetch           => "all",
	keyfield	=> "int13",
        template_id     => "205",
	int13           => ">::0",
 };
 $pref->{txt22} = "ilike::$serialnr%" if($serialnr);
 my $record = $dbt->fetch_record($dbh,$pref);
 return $record;
}

#get last (end_time) device locally in contenttranspos to get end_time of last state
sub get_devicesONcontenttranspos {
 my $dbh = shift;
 my $deviceId = shift;
 my $pref = {
        table           => "contenttranspos",
        fetch           => "one",
	order		=> "end_time",
	int13           => "$deviceId",
 };
 my $record = $dbt->fetch_tablerecord($dbh,$pref);
 return $record;
}


#get one device localy
sub get_devicesONcontent {
 my $dbh = shift;
 my $deviceId = shift;
 my $pref = {
        table           => "content",
        fetch           => "one",
        template_id     => "205",
	int13           => "$deviceId",
 };
 my $record = $dbt->fetch_record($dbh,$pref);
 return $record;
}

#get and check if theft exist in contenttranspos not older than 1 day
sub get_devicesONcontenttheftpos {
 my $dbh = shift;
 my $key = shift;
 my $id = shift;
 my $end_time = shift || "";

 my $pref = {
        table  => "contenttheftpos",
        fetch  => "one",
	$key  => "$id",
 };
	
 $pref->{end_time} = ">=::$end_time" if($end_time);

 my $record = $dbt->fetch_tablerecord($dbh,$pref);
 return $record;
}


sub get_devices {
 my $dbh = shift;
 my $op_name = shift;
 my $endpoint = "https://tracking.ilockit.bike/api/devices";
 my $rest = "";

 my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest);
 my $response_in = {};
 $response_in = decode_json($ret_json);

 print FILE "ilockit get_devices response_in:" . Dumper($response_in);

 my $pref = {
        table           => "content",
        fetch           => "all",
        keyfield        => "barcode",
        template_id     => "205",
	#int10           => "1",#1 = "available"
   };
 my $record = $dbt->fetch_record($dbh,$pref);
 my $rows = 0;
 if(1==1 && ref($response_in) eq "ARRAY"){
   foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){
     foreach my $resp (sort { $a->{id} <=> $b->{id} } (@{ $response_in })) {
       #print "if($resp->{name} eq $record->{$id}->{txt18} && ($resp->{id} && $resp->{id} ne $record->{$id}->{int13}))\n";
       if($resp->{name} eq $record->{$id}->{txt18} && ($resp->{id} && $resp->{id} ne $record->{$id}->{int13})){
          my $update = {
                table   =>      "content",
                mtime   =>      "now()",
                owner   =>      "$owner",
		int13   =>	"$resp->{id}",
          };
          $rows = $dbt->update_record($dbh,$update,$record->{$id});
          print FILE "update_record content.int13=$resp->{id}" . $rows . "\n";
       }
     }
   }
 }

}#end get_devices


#get_events
sub get_events {
 my $dbh = shift;
 my $op_name = shift;
 my $response_in = shift;

 #1. select all devices on content
 print FILE "ilockit get_events get_devicesONcontent_all\n";
 my $record_cc = get_devicesONcontent_all($dbh,"");
 my $today = DateTime->now( time_zone => "Europe/Berlin" );

 #$today .= "Z";
 #my $from_datetime = DateTime->now( time_zone => "Europe/Berlin" );
 #$from_datetime->subtract( days => 1 );
 #$from_datetime .= "Z";
 #my $endpoint = "https://tracking.ilockit.bike/api/reports/events";
 #my $rest = "from=2021-05-31T07:44:10Z\&to=2021-06-06T07:44:10Z\&deviceId=4272"; 
 #my $rest = "from=2021-06-11T07:44:10Z\&to=2021-06-11T12:44:10Z\&deviceId=$deviceId"; 
 
 #2. loope content to get deviceId
 foreach my $id (sort { $record_cc->{$a}->{barcode} <=> $record_cc->{$b}->{barcode} } keys (%$record_cc)){
  
   #get Ilockit events by deviceId
   #my $rest = "from=$from_datetime\&to=$today\&deviceId=$record_cc->{$id}->{int13}"; 
   #my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest);
   #$response_in = decode_json($ret_json);
   #print FILE "ilockit get_events response_in:" . Dumper($response_in);
 
   foreach my $resp (sort { $a->{id} <=> $b->{id} } (@{ $response_in })) {
     #if($record_cc->{$id}->{int13} eq $resp->{deviceId} && $resp->{type} eq "deviceOnline"){
     if($record_cc->{$id}->{int13} && $record_cc->{$id}->{int13} eq $resp->{deviceId} && $resp->{type} eq "lockStatus" && ref($resp->{attributes}) eq "HASH" && $resp->{attributes}->{statusCode}){
	my $theft_record = { c_id => 0 };
        $theft_record = get_devicesONcontenttheftpos($dbh,"int01",$resp->{id},"");#Alarm detected

	print FILE "shareeTime: $today\n";
	print FILE "bike: $op_name->{oprefix}$record_cc->{$id}->{barcode}\n";
	print FILE "id: $resp->{id}\n";
	print FILE "deviceId: $resp->{deviceId}\n";
	print FILE "type: $resp->{type}\n";
	print FILE "statusCode: $resp->{attributes}->{statusCode}\n";
	print FILE "serverTime: $resp->{serverTime}\n\n";

	my $int05 = 0;
	my $txt10 = $resp->{attributes}->{statusCode};
	if($resp->{attributes}->{statusCode} eq "alarm"){
	  $int05 = 7;
	}
	#insert theft alarm if no theft alarm with theft id 
        if(!$theft_record->{c_id}){
	 my $serverTime = localizedtime($resp->{serverTime});
	 my $insert = {
          table   =>      "contenttheftpos",
	  cc_id   =>	"$record_cc->{$id}->{c_id}",
	  barcode =>	"$record_cc->{$id}->{barcode}",
	  int04	  =>	"$record_cc->{$id}->{int04}",#end station
	  txt06	  =>	"$record_cc->{$id}->{txt06}",#end gps
	  txt10   =>	"$resp->{attributes}->{statusCode}",
	  txt18   =>    "$record_cc->{$id}->{txt18}",
          owner   =>      $owner,
          mtime   =>      "now()",
	  int05   =>	"$int05",#theft alarm
	  int01	  =>	"$resp->{id}",#keeps id for event_type
	  int13	  =>	"$resp->{deviceId}",
	  int10	  =>	"$record_cc->{$id}->{int10}",
	  int20	  =>	"$record_cc->{$id}->{int20}",
	  start_time => "$serverTime",
	  end_time => "$serverTime",
        };

	my $c_id = 0;
 	$c_id = $dbt->insert_contentoid($dbh,$insert);
   	print FILE "insert theft_record:" . Dumper($insert);
       }
     }
   }
  }
}#end get_events


sub get_positions {
 my $dbh = shift;
 my $op_name = shift;
 
 my $record_cc = get_devicesONcontent_all($dbh,"C2-04");
 my $endpoint = "https://tracking.ilockit.bike/api/positions";

 my $today = DateTime->now( time_zone => "Europe/Berlin" );
 $today .= "Z";
 my $interval = 3;
 my $from_datetime = DateTime->now( time_zone => "Europe/Berlin" );
 $from_datetime->subtract( minutes => $interval );
 $from_datetime = utctime($from_datetime,"0");
 $from_datetime .= "Z";

 #2. loope cloud
 foreach my $id (sort { $record_cc->{$a}->{barcode} <=> $record_cc->{$b}->{barcode} } keys (%$record_cc)){
  
  my $ctpos = { c_id => 0 };
  $ctpos = get_devicesONcontenttranspos($dbh,$record_cc->{$id}->{int13});#get last rental

  #checke also Ilockit lockStatus 
  my $theft_record_closed = { c_id => 0 };
  my $pref_th = {
        table  => "contenttheftpos",
        fetch  => "one",
	txt10  => "ilike::closed%",
	int13  => $record_cc->{$id}->{int13},
	end_time => ">::$ctpos->{end_time}",
  };
  $theft_record_closed = $dbt->fetch_tablerecord($dbh,$pref_th) if($ctpos->{end_time});

  #For Closed locks
  #if copri.locked OR Ilockit.closed, then get position in range of end_time to now
  if($record_cc->{$id}->{int13} && (($ctpos->{int20} && $ctpos->{int20} == 1) || $theft_record_closed->{c_id})){
   print FILE "get_position bike $ctpos->{ct_name} $ctpos->{int13} --> copri lock_state:$ctpos->{int20} end_time:$ctpos->{end_time} | Ilockit.statusCode: $theft_record_closed->{txt10}\n";

   #3 minutes until now last Alarm detected with deviceId
   my $theft_record_detect = { c_id => 0 };
   $pref_th = {
        table  => "contenttheftpos",
        fetch  => "one",
	int05  => 7,
	int13  => $record_cc->{$id}->{int13},
	end_time => ">=::(now() - interval '$interval min')",
   };
   #end_time => ">::$ctpos->{end_time}",
   $theft_record_detect = $dbt->fetch_tablerecord($dbh,$pref_th);
   print FILE "theft_record_detect bike: $theft_record_detect->{barcode} | $theft_record_detect->{c_id} | last end_time:$theft_record_detect->{end_time}\n";

   #get only positions if locked and last alarm before 3 minutes
   if($theft_record_detect->{c_id} && $ctpos->{int13} && $ctpos->{end_time} =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/){
    #$ctpos->{end_time}  =~ s/\..*$//;
    #my $end_time = $ctpos->{end_time};
    #$end_time =~ s/\s/T/;
    #my $from_datetime = utctime($end_time,"0");
    #$from_datetime .= "Z";

    my $rest = "from=$from_datetime\&to=$today\&deviceId=$record_cc->{$id}->{int13}"; 
    my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest);
    my $response_in = {};
    $response_in = decode_json($ret_json);
    print FILE "ilockit get_positions response_in:" . Dumper($response_in);
 
   my $theftmove_count = 0;
   foreach my $resp (sort { $a->{id} <=> $b->{id} } (@{ $response_in })) {
     print FILE "$resp->{id} shareeTime: $today | serverTime: $resp->{serverTime} | ilockit get_positions movement: $theft_record_detect->{barcode} | $record_cc->{$id}->{int13} eq $resp->{deviceId} && speed:$resp->{speed} && distance:$resp->{attributes}->{distance})\n";
     #if($record_cc->{$id}->{int13} eq $resp->{deviceId} && $resp->{speed} > 0 && $resp->{attributes}->{distance} >= 200)
     if($record_cc->{$id}->{int13} eq $resp->{deviceId}){
	$theftmove_count++;#count if move holds on for min 2 times
        my $theft_record = get_devicesONcontenttheftpos($dbh,"int02",$resp->{id},"");#Alarm movement
	print FILE "shareeTime: $today\n";
	print FILE "bike: $op_name->{oprefix}$record_cc->{$id}->{barcode}\n";
	print FILE "id: $resp->{id}\n";
	print FILE "deviceId: $resp->{deviceId}\n";
	print FILE "serverTime: $resp->{serverTime}\n\n";
	#if(!$theft_record->{c_id} && $theftmove_count >= 2)
        if(!$theft_record->{c_id}){
	 my $serverTime = localizedtime($resp->{serverTime});
	 my $insert = {
          table   =>      "contenttheftpos",
	  cc_id   =>	"$record_cc->{$id}->{c_id}",
	  barcode =>	"$record_cc->{$id}->{barcode}",
	  txt06	  =>	"$resp->{latitude}, $resp->{longitude}",
          owner   =>      $owner,
          mtime   =>      "now()",
	  int02	  =>	"$resp->{id}",#keeps id for event_type
	  int03	  =>	"$theftmove_count",
	  int07	  =>	"$resp->{speed}",
	  int08	  =>	"$resp->{attributes}->{distance}",
	  int05   =>	"8",#gps position marker
	  int13	  =>	"$resp->{deviceId}",
	  int10	  =>	"$record_cc->{$id}->{int10}",
	  int20	  =>	"$record_cc->{$id}->{int20}",
	  start_time => "$serverTime",
	  end_time => "$serverTime",
        };

	my $c_id = 0;
 	$c_id = $dbt->insert_contentoid($dbh,$insert);
   	print FILE "insert sub get_positions:" . Dumper($insert);
	print FILE "send_alarm2hotline condition: syshost:$op_name->{syshost}, c_id:$c_id && $theftmove_count > $dbt->{copri_conf}->{theftalarm}->{move_count} && ($resp->{speed} > $dbt->{copri_conf}->{theftalarm}->{speed} && $resp->{attributes}->{distance} > $dbt->{copri_conf}->{theftalarm}->{meter})\n";

	#theft mailing
	if($c_id && $theftmove_count > $dbt->{copri_conf}->{theftalarm}->{move_count} && ($resp->{speed} > $dbt->{copri_conf}->{theftalarm}->{speed} && $resp->{attributes}->{distance} > $dbt->{copri_conf}->{theftalarm}->{meter})){
	 #send mail   
	 #max ~ 10 mails && cargobike && not in Archive
	 if($theftmove_count < 10  && $record_cc->{$id}->{type_id} == 300101 && !$record_cc->{$id}->{archive}){
	   system("$dbt->{copri_conf}->{basedir}/$op_name->{syshost}/src/scripts/mailTransportcms.pl '$op_name->{syshost}' 'send_alarm2hotline' '1' '$c_id' ''");
   	   print FILE "$dbt->{copri_conf}->{basedir}/$op_name->{syshost}/src/scripts/mailTransportcms.pl '$op_name->{syshost}' 'send_alarm2hotline' '1' '$c_id' ''\n\n";
	   #only if locked
	   if($op_name->{sms_alert} && $record_cc->{$id}->{int20} == 1){
	     system("$dbt->{copri_conf}->{basedir}/$op_name->{syshost}/src/scripts/sms_message.pl '$op_name->{syshost}' 'send_alarm2hotline' '' '$c_id'");
   	   }
 	 }
	}

       }
     }
    }
   }
  }
 }

}#end get_positions


#ilockit http request
sub fetch_ilockit_cloud {
 my $self = shift;
 my $ilockitserver = shift || "";
 my $rest = shift || "";
 my $ilockit_request = "$ilockitserver?$rest";

 print FILE "fetch_ >> " . $ilockit_request . "\n";

 my $req = HTTP::Request->new(GET => "$ilockit_request");
 #$req->content_type('application/x-www-form-urlencoded');
 $req->content_type('application/json');
 $req->content($rest);

 my $res = $ua->request($req);
 if ($res->is_success) {
  #print $res->content;
  return $res->content;
  print $res->status_line, "\n";
 }else {
  print $res->status_line, "\n";
 }
}

close(FILE);

