package LIMS::Controller::Admin::Screen::Test;

use strict;

use base 'LIMS::Controller::Admin';

use Moose;
	with 'LIMS::Controller::Roles::DataMap';
__PACKAGE__->meta->make_immutable(inline_constructor => 0);

__PACKAGE__->authz->authz_runmodes(	':all' => 'do_admin' );

#-------------------------------------------------------------------------------
sub list : StartRunmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);

    # get screens table data in list mode:
    my $screens = $self->stash->{screens_data} # stashed for _check_required_data()
        = $self->model('Screen')->get_all_screens({ sort_by => 'description' }); # DEBUG $screens;

    # need to have at least 1 of each lab test, screening term & lab section defined:
    $self->_check_required_data
        || return $self->forward('missing_data'); # returns true if OK

    # a re-direct from update() passes id as param:
    if ( my $id = $self->param('id') ) {
        $self->query->param(id => $id); # for next section and default.tt
    }

    # if we have a screening term selected:
    if ( my $screen_id = $self->query->param('id') ) { # warn 'screen_id:'.$screen_id;
        my $lab_tests = $self->_lab_tests($screen_id); # hash of arrayrefs
		$self->tt_params( lab_tests => $lab_tests );
		
		# get assigned section details for this screen_id:
		my $sections_details_map
			= $self->_assigned_test_details($screen_id); # $self->debug($sections_details_map);
		$self->tt_params( section_details_map => $sections_details_map );
		
		my $lab_sections_map = $self->lab_sections_map;
		$self->tt_params( lab_sections_map => $lab_sections_map );
    }

    # hash of screening terms: keys = tissue_type, vals = hashref of id & initial_screen_term
    {
		my %screens;
		foreach my $screen ( @$screens ) {
			my $type    = $screen->sample_type;
			my $details = {
				id   => $screen->id,
				term => $screen->description,
			};
	
			push @{ $screens{$type} }, $details;
		}
		$self->tt_params( screening_list => \%screens );
	}
	
	$self->csrf_insert_token;
	
    return $self->tt_process('admin/screen/test/default.tt');
}

#-------------------------------------------------------------------------------
sub update : Runmode { 
    my $self = shift; $self->_debug_path($self->get_current_runmode);

    my $screen_id = $self->param('id')
	|| return $self->error('no id passed to '.$self->get_current_runmode);

    unless ( $self->csrf_check_token ) {
        return $self->tt_process('site/csrf_error.tt');
	}

    my @test_ids = $self->query->param('test_id'); # DEBUG @test_ids;

    unless (@test_ids) {
        $self->flash( warning => $self->messages('screen')->{empty_screen_list} );
    }

	# collect any lab-section details separately:
	my $details = $self->_get_lab_section_details();
	
    my %args = (
        screen_id => $screen_id,
        test_ids  => \@test_ids,
		details   => $details,
    );

    # update lab_test entries for this screen_id:
    my $rtn = $self->model('Screen')->update_lab_tests(\%args); # DEBUG $rtn;

    return $rtn  ?
        $self->error($rtn) :
            $self->redirect( $self->query->url . '/admin/screen_test/list/'.$screen_id );
}

#-------------------------------------------------------------------------------
# if any lab section details submitted, create hash of lab_section_id => value:
sub _get_lab_section_details {
	my $self = shift; # $self->debug($self->param); 
	
	my $params = $self->query->Vars; # can't use $dfv->valid for dynamic params
	
	my %map;
	while ( my($param, $value) = each %$params ) {
		# look for param lab_section_id_(\d):
		my ($lab_section_id) = $param =~ /lab_section_id_(\d+)/; # don't do '|| next' here
		next unless $lab_section_id;
		
		$map{$lab_section_id} = $value;
	} # $self->debug(\%map);
	
	return \%map;
}

#-------------------------------------------------------------------------------
# return hash: keys = section_name, vals = ref to array of { lab_test_id, lab_test_name, lab_test_field_name, active }
sub _lab_tests {
    my $self      = shift; $self->_debug_path('_lab_tests');
    my $screen_id = shift || die 'No screen_id value passed to _lab_tests()';

    my %lab_tests;

    # get details of all tests in lab_tests table:
    my $data = $self->model('LabTest')->get_all_active_lab_tests; # returns iterator

    # get assigned lab_tests for this screen_id:
    my $assigned_lab_tests_ids = $self->_assigned_lab_tests($screen_id); # arrayref of lab_test_ids

    while ( my $test = $data->next ) { # DEBUG $test->lab_section->section_name;
        my $section_name = $test->lab_section->section_name;

		my $data = $test->as_tree;

        # if the test_id matches an assigned test_id, set field to 'selected' for template:
        if ( grep { $test->id == $_ } @$assigned_lab_tests_ids ) {
            $data->{selected} = 1;
        }

        push @{ $lab_tests{ $section_name } }, $data;
    } # $self->debug(\%lab_tests);

    return \%lab_tests;
}

#-------------------------------------------------------------------------------
sub _assigned_lab_tests {
    my $self      = shift; $self->_debug_path('_assigned_lab_tests');
    my $screen_id = shift || die 'No screen_id value passed to _assigned_lab_tests()';

    my $assigned_tests = $self->model('Screen')->get_assigned_tests($screen_id);

    my @assigned_lab_tests_ids = map { $_->lab_test_id } @$assigned_tests; # DEBUG \@assigned_lab_tests_ids;

    return \@assigned_lab_tests_ids;
}

#-------------------------------------------------------------------------------
sub _assigned_test_details {
    my $self      = shift; $self->_debug_path('_assigned_test_details');
    my $screen_id = shift || die 'No screen_id value passed to _assigned_test_details()';

    my $test_details = $self->model('Screen')->get_assigned_test_details($screen_id);

    my %test_details = map {
        $_->lab_section_id => $_->test_details;
    } @$test_details; # DEBUG \%test_details;

    return \%test_details;
}

#-------------------------------------------------------------------------------
sub _check_required_data {
    my $self = shift; $self->_debug_path('_check_required_data');

    # first check we have at least 1 lab section defined:
	unless ($self->have_lab_sections) {
        $self->stash( error_msg => $self->messages('admin')->{no_sections} );
        return 0;
    }

    # check we have at least one lab test defined:
	unless ($self->have_lab_tests) {
        $self->stash( error_msg => $self->messages('admin')->{no_tests} );
        return 0;
    }

    # require at least 1 screening term to allocate lab tests to:
    my $screens = $self->stash->{screens_data};

    unless (@$screens) {
        $self->stash( error_msg => $self->messages('admin')->{no_screens} );
        return 0;
    }

    # OK, passed all tests:
    return 1;
}

1;
