use strict;
use warnings;

=begin
to use: 
config in /usr/local/hl7/hl7d.conf
plugins /usr/local/hl7/plugins
start hl7d: cd /usr/local/hl7d; sudo perl -T hl7d.pl --nodetach --debug
run hl7.pl (uses HILIS), or: t/report_status.t, then perl hl7.pl 2 (uses lims_test)
=cut

use lib '/home/raj/apps/HILIS4/lib';
use FindBin qw($Bin); # warn $Bin; exit;

use LIMS::Local::ScriptHelpers;
use LIMS::Local::Stuff;
use LIMS::Local::Utils;
use LIMS::Local::HL7;

use Data::Dumper;
use Net::HL7::Connection;

# ==============================================================================
my $hl7d_addr = '127.0.0.1'; # '163.160.104.248' # TIE
my $hl7d_port = 12002; # 7210;
#my $hl7d_addr = '163.160.104.248'; # TIE
#my $hl7d_port = 7210;

my @request_id = $ARGV[0] || 101111; # anon hiv
push @request_id, 188067; # Flow & Molecular results, with new-line in comment causing problem
# ==============================================================================

open my $hl7_log, '>', $Bin . '/hl7_log.txt' or die $!;
open my $hl7_ice, '>', $Bin . '/hl7_ice.txt' or die $!;

my $tools = LIMS::Local::ScriptHelpers->new();

my $now = LIMS::Local::Utils::time_now();

my $cfg_file = "$Bin/crons/lib/settings.cfg";
my $settings = Config::Auto::parse($cfg_file); # warn Dumper $settings; exit;
# add HL7d to settings - TODO: hard-code to cfg_file
$settings->{hl7d_addr} = $hl7d_addr;
$settings->{hl7d_port} = $hl7d_port;

# get tools from LIMS::Local::ScriptHelpers:
my $sql_lib = $tools->sql_lib(); # warn Dumper $sql_lib->elements; 
my $config  = $tools->config();
my $dbix    = $tools->dbix();

# increase max length of group_concat; permitted range (32-bit system) 4 .. 4294967295
$dbix->dbh->do('SET group_concat_max_len = 3072'); 

#$dbix->dbh->do('use lims_test') if $request_id < 5;
# redo_summary(); ONLY DO THIS IF USING TEST DB !!!!

# get sql statments:
my $sql = _get_sql();
my $result = $dbix->query($sql, @request_id); # warn Dumper \@request_id;

# args for LIMS::Local::HL7->new():
my $hl7_socket = _build_hl7_socket(); # open connection to hl7 server once only
my @hl7_args = ( settings => $settings, hl7_socket => $hl7_socket );

my $i = 0; # auto-incrementing message id

while ( my $vars = $result->hash ) { # warn Dumper $vars; next;
    my $hl7 = LIMS::Local::HL7->new(@hl7_args); # pass socket & settings args

	# build HL7 message:
	$hl7->build_msh_segment(++$i);	# message id counter
	$hl7->build_pid_segment($vars);	
	$hl7->build_obr_segment($vars);	
	
	# add report (comment, diagnosis, etc) to HL7 message:
	_build_report($hl7, $vars); 

	# message should now be complete, send it
    my $response = $hl7->send_message(); # warn $response;

    # dump msg, vars & response to log:
    my $msg = $hl7->msg(); # warn $msg->toString(1); # Net::HL7::Request object
	dump_msg($vars, $msg, $response);
}

$hl7_socket->close();

# ------------------------------------------------------------------------------
sub _build_report {
	my ($hl7, $vars) = @_;	
	
    # create text string from samples code(s):
    $vars->{specimen_type} = $hl7->specimen_summary($vars->{sample_code});

    my @report = (
        [ 'Specimen type',      $vars->{specimen_type}     ],
        [ 'Specimen quality',   $vars->{specimen_quality}  ],
        [ 'Gross description',  $vars->{gross_description} ],
        [ 'Results summary',    $vars->{result_summaries}  ],
        [ 'Clinical details',   $vars->{clinical_details}  ],
        [ 'Morphology/comment', $vars->{comment}           ],
        [ 'Diagnosis',          $vars->{diagnosis}         ],
        [ 'ICDO3',              $vars->{icdo3}             ],
    );

	my $i = 0; # incremental OBX counter
    $hl7->build_obx_segment(@$_, ++$i) for @report; # field, value, counter
}

# ------------------------------------------------------------------------------
sub _build_hl7_socket {
	# open HL7 connection via socket
    my ($addr, $port) = @{$settings}{ qw(hl7d_addr hl7d_port) };
	my $socket = new Net::HL7::Connection($addr, $port)
		or die "Could not connect to HL7d $addr on port $port: $!";
	return $socket;
}

# ------------------------------------------------------------------------------
sub dump_msg { #  write to interface logs
	my ($vars, $msg, $response) = @_;
    
#	my $dow = $now->day_name; # warn $dow;
    my $request_number = _get_request_number($vars);

    printf $hl7_log "%s: %s\n\n", $request_number, $response;
	print  $hl7_log $msg->toString(1)."\n";
	print  $hl7_log Dumper $msg;

	printf $hl7_ice "H%s %s\n",	$request_number, '=' x 100;
	while ( my @pair = map { $_ ||= 'NULL' } each %$vars ) {
		printf $hl7_ice "%s: %s\n", @pair;
	}
}

# ------------------------------------------------------------------------------
sub redo_summary {
	my $line = LIMS::Local::Stuff::silly_werder(10,20); # warn length $line;
    # add some chars for escaping:
    $line .= ' and & and ^ and \ and | and ~ end.';
	$dbix->update('request_result_summaries',
		{ results_summary => $line }, { request_id => 2 });
}

# ------------------------------------------------------------------------------
sub _get_request_number {
	my $vars = shift;
	return join '/', $vars->{request_number}, $vars->{year} - 2000;
}

# ------------------------------------------------------------------------------
sub _get_sql {
return q!
SELECT 
    p.last_name,
    p.first_name,
    p.middle_name,
    p.dob,
    p.nhs_number,
	p.gender,
    pc.unit_number,
    src.display_name as 'location',
	src.organisation_code,
    rf.name as 'referrer_name',
	rf.national_code as 'referrer_code',
    req.id as 'request_id',
    req.request_number,
    req.year,
    req.created_at,
	req.updated_at,
    rr.status,
	rr.comment,
	rr.clinical_details,
	rr.specimen_quality,
	rr.gross_description,
	GROUP_CONCAT(DISTINCT(s.`sample_code`)) as 'sample_code',
	GROUP_CONCAT(DISTINCT(s.`description`) separator '/') as 'sample_description',
    d.name as 'diagnosis',
	d.icdo3,
	GROUP_CONCAT( DISTINCT ls.section_name, ': ', rrs.results_summary SEPARATOR "\n" )
		as 'result_summaries',
	MAX(CASE WHEN h.action = 'reported' THEN u.username END) as 'report_by',	
	MAX(CASE WHEN h.action = 'reported' THEN date(h.time) END) as 'report_date',	
	MAX(CASE WHEN h.action = 'authorised' THEN u.username END) as 'auth_by',
	MAX(CASE WHEN h.action = 'authorised' THEN date(h.time) END) as 'auth_date'
FROM
    requests req
    JOIN ( patient_case pc JOIN patients p on pc.patient_id = p.id )
        on req.patient_case_id = pc.id
    JOIN referral_sources src on pc.referral_source_id = src.id
    JOIN ( referrer_department rd JOIN referrers rf on rd.referrer_id = rf.id )
        on req.referrer_department_id = rd.id  
	JOIN ( request_history h JOIN users u on h.user_id = u.id )
        on h.request_id = req.id	
    JOIN ( request_report_view rr JOIN diagnoses d on rr.diagnosis_id = d.id )
        on rr.request_id = req.id    
	JOIN ( request_specimen rs JOIN specimens s on rs.`specimen_id` = s.id )
        on rs.`request_id` = req.id	
	LEFT JOIN ( request_result_summaries rrs join lab_sections ls 
		on rrs.`lab_section_id` = ls.id )  on rrs.`request_id` = req.id
WHERE req.id in (??)
GROUP BY req.id
!;
}
	