package Outreach;

use Moose;
with qw(
	Role::RebuildTables
	Role::ReferralSource
);

use namespace::clean -except => 'meta';

use Data::Dumper;

has $_ => (is => 'ro', isa => 'HashRef', required => 1)
	foreach qw( db sql );

has log_file => ( is => 'ro', required => 1 );
has request_id_map => ( is => 'rw', isa => 'HashRef[Str]', default => sub { {} });

__PACKAGE__->meta->make_immutable;

$|++;

# abbr. for db name:
my $CM = 'community_monitoring';

# rebuilds:
# biochemistry, flow_cytometry, followup_decisions, haematology, immunology,
# pack_dispatches, patient_details, questionnaire_*
# need to manually copy 'static' data tables:
# alternate_address, defaults_and_ranges, followup_options, menu_fields,
# non_participant_practices

sub convert { 
    my $self = shift;
	
    # retain case-sensitivity of cols (CHANGES $DB::dbix3 SO MUST REVERSE THIS AFTER):
    $self->db->{dbix3}->lc_columns = 0;

	$self->do_patient_details(); 
	$self->do_followup_decisions();
	$self->do_lab_params();
	$self->do_pack_dispatches();
	$self->do_questionnaires();
	
	$self->db->{dbix3}->lc_columns = 1; # reset to default
}

sub do_followup_decisions {
    my $self = shift;

    my $dbix3 = $self->db->{dbix3};
    my $dbix4 = $self->db->{dbix4};
    my $dbh4 =  $self->db->{dbh4};
    
	my $table = 'outreach.followup_decisions';
	
	# need to remove FK first:
	$dbh4->do( qq!ALTER TABLE $table DROP FOREIGN KEY `followup_decisions_ibfk_1`! );
	
	$self->clear_table($table);

	# followup_decisions map:
	my $followup_decisions_map
		= $dbix3->query(qq!select `option`, `id` from $CM.followup_options!)->map;
	
	# followup_decisions table:
	my $sql = qq!select m.HMDS, year(m.Date) as 'YEAR', fd.*
		from $CM.followup_decisions fd left join Main m on fd.dbid = m.DBID!;
		
	my $query = $dbix3->query($sql);
	while ( my $vals = $query->hash ) {
		# get request_id or skip (will have warned to output):
		my $request_id = $self->_get_request_id($vals) || next;
		
		my $decision = $vals->{decision};
		
		my %data = (
			request_id => $request_id,
			followup_option_id => $followup_decisions_map->{$decision},
			time => $vals->{timestamp},
		);
		$dbix4->insert($table, \%data);
	}
	
	# restore FK:
	$dbh4->do( qq!ALTER TABLE $table ADD CONSTRAINT `followup_decisions_ibfk_1`
		FOREIGN KEY (`followup_option_id`) REFERENCES `followup_options` (`id`)! );
}
	
sub do_lab_params {
	my $self = shift;
	
    my $dbix3 = $self->db->{dbix3};
    my $dbix4 = $self->db->{dbix4};
	
	my $table = 'outreach.request_results';
	
	$self->clear_table($table);

	my $params_map
		= $dbix4->query(q!select param_name, id from outreach.lab_params!)->map;
	# warn Dumper $params_map; exit;
		
	# create data structure for all departments:
	my %data = ();
	
	my @depts = qw(biochemistry immunology haematology flow_cytometry);
	
	foreach my $dept (@depts) {
		my $sql = qq!select m.HMDS, year(m.Date) as 'YEAR', tbl.*
			from $CM.$dept tbl left join Main m on tbl.dbid = m.DBID!;
		my $query = $dbix3->query($sql);
		
		while ( my $vals = $query->hash ) {
			# get request_id or skip (will have warned to output):
			my $request_id = $self->_get_request_id($vals) || next;

			while ( my ($param, $val) = each %$vals ) { # warn Dumper [ $param, $val ];
				next if grep $param eq $_, qw(dbid HMDS YEAR); # ie non-tests
				next unless $val; # skip null cols
				
				my $param_id = $params_map->{$param} or die "no param id for $param";
				$data{$request_id}{$param_id} = $val;
			}			
		}
	}
	
	while ( my ($request_id, $results) = each %data ) { # warn Dumper [ $request_id, $results ];
		while ( my ($param_id, $val) = each %$results ) {
			my %data = (
				request_id => $request_id,
				param_id   => $param_id,
				result     => $val,
			);
			$dbix4->insert($table, \%data);
		}
	}	
}

sub do_pack_dispatches {
	my $self = shift;
	
    my $dbix3 = $self->db->{dbix3};
    my $dbix4 = $self->db->{dbix4};
	
	my $table = 'outreach.pack_dispatches';
	
	$self->clear_table($table);

	my $sql = qq!select m.HMDS, year(m.Date) as 'YEAR', pd.*
		from $CM.pack_dispatches pd left join Main m on pd.dbid = m.DBID!;
		
	my $query = $dbix3->query($sql);
	while ( my $vals = $query->hash ) {
		# get request_id or skip (will have warned to output):
		my $request_id = $self->_get_request_id($vals) || next;

		my %data = (
			request_id => $request_id,
			date_due   => $vals->{date_due},
			date_sent  => $vals->{date_sent},
			time 	   => $vals->{timestamp},
		);
		$dbix4->insert($table, \%data);
	}	
}

sub do_patient_details {
	my $self = shift;
	
    my $dbix3 = $self->db->{dbix3};
    my $dbix4 = $self->db->{dbix4};
	
	my $table = 'outreach.patient_details';
	
	$self->clear_table($table);
	
	# get organisation_codes like '[^BCY]____' from referral_sources:
	my $practices_map = $self->referral_source_practices;
	# get national_code like 'G%' from referrers:
	my $practitioners_map = $self->_get_practitioners_map;
	# get distinct community_monitoring.practice_id's (ie org_code):
	my $cm_practices = $dbix3->query(
        q!select distinct(practice_id) from community_monitoring.patient_details
        where practice_id is not null and practice_id <> 'B00000'!
    )->flat;
	# warn Dumper $cm_practices; 

	# get referrer.id for unknown gp:
	$dbix4->query(q!select id from referrers where national_code = 'G9999998'!)
		->into( my $unknown_gpid); # warn $unknown_gpid;
	# get referral_source.id for unknown practice:
	$dbix4->query(q!select id from referral_sources where organisation_code = 'V81999'!)
		->into( my $unknown_practice_id); # warn $unknown_practice_id; 
	
	# ensure all practices in cm.patient_details exist in referral_sources:
	$self->add_new_practices_to_referral_sources($cm_practices); 
	# check GP's from cm.patient_details exist in referrers - just prints warning:
	$self->_check_outreach_practitioners($practitioners_map); 

	my $sql = qq!select * from $CM.patient_details!; # don't need join
	
	my $query = $dbix3->query($sql);
	while ( my $vals = $query->hash ) {
		my $practice_code = $vals->{practice_id} || ''; # actually org code
		my $gp_code = $vals->{gp_id} || ''; # actually GMC number
		
		my $practice_id = $practices_map->{$practice_code};
		#	|| warn "no practice_id for $practice_code"; # WRONG - GETS SET TO '1'
		if (! $practice_id) { #	warn "no practice_id for $practice_code";
			$practice_id = $unknown_practice_id; # warn "$practice_code:$practice_id";
		}

		my $practitioner_id = $practitioners_map->{$gp_code} || $unknown_gpid;
		
		# replace gp_id & practice_id with real values:
		$vals->{gp_id} = $practitioner_id;
		$vals->{practice_id} = $practice_id;
		
		$dbix4->insert($table, $vals);
	}	
}

sub do_questionnaires {
	my $self = shift;
	
    my $dbix3 = $self->db->{dbix3};
    my $dbix4 = $self->db->{dbix4};
	
	my @tables = qw(
		questionnaire_pain
		questionnaire_details
		questionnaire_symptoms
		questionnaire_locality
		questionnaire_adenopathy
		questionnaire_treatment );
	
	for my $table (@tables) {
		$self->clear_table("outreach.$table");
		
		my $sql = qq!select m.HMDS, year(m.Date) as 'YEAR', tbl.*
			from $CM.$table tbl left join Main m on tbl.dbid = m.DBID!;
	
		my $query = $dbix3->query($sql);
	
		while ( my $vals = $query->hash ) {
			# get request_id or skip (will have warned to output):
			my $request_id = $self->_get_request_id($vals) || next;

			# remove unwanted vals, add $vals->{request_id}:
			$vals->{request_id} = $request_id;
			map delete $vals->{$_}, qw(dbid HMDS YEAR);
			
			$dbix4->insert("outreach.$table", $vals);
		}
	}
}

sub _get_request_id {
	my ($self, $vals) = @_;	
	
	my $dbid = $vals->{dbid};
	
	if ( my $request_id = $self->request_id_map->{$dbid} ) {
		return $request_id;
	}
	
	my $dbix4 = $self->db->{dbix4};
	my $request_id = $dbix4->query( q!select id from requests where request_number
		= ? and year = ?!, $vals->{HMDS}, $vals->{YEAR} )->list;
	
	if (! $request_id) {
		warn "no request_id for $dbid [" . $vals->{HMDS} . '/' . $vals->{YEAR} . ']';
		return 0; 
	}
	
	# stash it for next time:
	$self->request_id_map->{$dbid} = $request_id;
	return $request_id;
}

sub _get_practitioners_map {
	my $self = shift;
	
	my $sql = q!select national_code, id from referrers
		where national_code like 'G%'!;
	
	return $self->db->{dbix4}->query($sql)->map;
}

sub _check_outreach_practitioners {
	my ($self, $practitioners_map) = @_; # warn Dumper $practitioners_map; 
	
    my $dbix3 = $self->db->{dbix3};

	my $log_file = $self->log_file;

	my $cm_practitioners
		= $dbix3->query(qq!select distinct(gp_id) from $CM.patient_details
			where gp_id is not null!)->flat;
	# warn Dumper $cm_practitioners;
	
	my @unknown_gps;
	
	for my $gp_code (@$cm_practitioners) {
		push @unknown_gps, $gp_code unless $practitioners_map->{$gp_code};
	}
	
	if (@unknown_gps) {
		print $log_file "outreach GP's not in referrers table:\n";
		print $log_file Dumper \@unknown_gps;
	}
}

1;