package LIMS::Controller::WorkList;

use base 'LIMS::Base';

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

use Data::Dumper;

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

	my $active_sections = $self->model('WorkList')->get_active_sections_list;
	my $request_status_options = $self->request_status_options_map;

	# locally defined worklists:
	if ( my $yaml = $self->get_yaml_file('local_worklists') ) { # warn Dumper $yaml;
		$self->tt_params( local_worklists => $yaml );
	}

	# print labels:
	if ( my $yaml = $self->get_yaml_file('print_labels') ) {
		$self->tt_params( print_labels => $yaml );
	}

    $self->tt_params(
		active_sections => $active_sections,
		request_status_options => $request_status_options,
	);

	return $self->tt_process;
}

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

	# don't need ValidateRM->check() as vars passed automatically on submit:
	my $profile = $self->validate('worklist');
    my $data = $self->get_data_from_dfv($profile); # $self->debug($data);

	my $lab_section_id = $data->{lab_section_id}
	|| return $self->redirect( $self->query->url . '/worklist' );

	{ # active investigations for this section:
		my $investigations = $self->model('WorkList')
			->get_active_investigations_for_section($lab_section_id);
		$self->tt_params( active_investigations => $investigations );
	}
	{ # lab_test status_options for this section:
		my $section_status_options
			= $self->get_status_options_for_select($lab_section_id);
		$self->tt_params( status_options => $section_status_options );
	}
	# get list of lab sections to require clinical trial filter
	if ( my $cfg = $self->get_yaml_file('worklist_cfg') ) { # warn Dumper $cfg;
		# check it's generating hashref or die (can't return $self->error here):
		die "yml doesn't return hashref" unless ref $cfg eq 'HASH';
		if ( my $sections = $cfg->{clinical_trial_filter}{lab_sections} ) { # warn Dumper $sections;
			$self->tt_params( exclude_clinical_trial_sections => $sections );
		}
	}

	# return to default() to load lab_sections & re-display:
	return $self->forward('default');
}

# ------------------------------------------------------------------------------
# for dashboard lab-test status charts, retrieves section.id for param 'id', and
# status_option.id & lab_test.id for query params & forwards to display():
sub test_status : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);

	my $vars = $self->query->Vars();

	my ($status_option, $section_name, $test_name)
		= map $vars->{$_}, qw(status section_name lab_test);
	# warn Dumper [$status_option, $section_name, $lab_test];

	my $section = $self->model('LabSection')
		->get_lab_section_by_name($section_name);
	# display() expects lab_section.id passing as param 'id':
	$self->param( id => $section->id ); # lab_section.id

	{ # lab_test.id as query param:
		my %args = ( lab_section_id => $section->id, lab_test => $test_name );
		my $lab_test = $self->model('LabTest')->get_section_lab_test(\%args);
		$self->query->param( lab_test_id => $lab_test->id );
	}
	{ # lab_test_status_option.id as query param:
		my $options_map = $self->lab_test_status_options_map('description');
		my $option_id = $options_map->{$status_option}->{id}; # warn Dumper $option_id;
		$self->query->param( status_option_id => $option_id );
	}

	return $self->forward('display');
}

# ------------------------------------------------------------------------------
sub display : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);
	my $errs = shift; # $self->stash( errs => $errs ); # warn Dumper $errs;

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

	# don't need ValidateRM->check() as vars passed automatically on submit:
	my $profile = $self->validate('worklist');
	my $data = $self->get_data_from_dfv($profile); # warn Dumper $data;

	# do NOT want status_option_id if returning from update_results() with error:
	delete $data->{status_option_id} # status_option_id is the one to update *to*
		if $self->query->param('results_entry');

	# put lab_section_id into $data for model:
	$data->{lab_section_id} = $lab_section_id; # $self->debug($data);

	{ # get lab_section data:
		my $lab_section = $self->model('LabSection')->get_lab_section($lab_section_id);
		$self->tt_params( lab_section => $lab_section );

		# stash lab_section for request_section_notes_map() & template:
		$self->stash( lab_section => $lab_section );
	}

	my $work = $self->model('WorkList')->get_outstanding_investigations($data);

	# check we have something to do - status_option_id restriction might have been applied
	unless (@$work) {
		my $msg;
		if ( my $status_option_id = $data->{status_option_id} ) {
			my $status_option
				= $self->model('LabTest')->get_status_option($status_option_id);
			$msg = sprintf $self->messages('worklist')->{no_tests_for_status},
				uc $status_option->description;
		}
		else { # shouldn't fail if not status_option restricted, but just in case:
			$msg = sprintf $self->messages('worklist')->{no_outstanding_tests},
				$self->stash->{lab_section}->section_name;
		}
		$self->flash ( info => $msg );
		my $destination =  '/worklist/select?lab_section_id=' . $lab_section_id;
		return $self->redirect($self->query->url . $destination);
	}

	{ # convert objects to hashrefs to prevent template lookups:
		my @data = map { $_->as_tree(deflate => 0) } @$work; # preserve datetime
		$self->tt_params( outstanding_investigations => \@data );
	}

	# get some data maps for tmpl:
	{
		my $unique_ids = $self->get_unique_request_ids($work); # arrayref of request_ids

		{ # specimens:
			my $map = $self->specimen_map($unique_ids);
			$self->tt_params( specimen_map => $map );
		}
		{ # request_options:
			my $map = $self->request_options_map($unique_ids);
			$self->tt_params( request_options_map => $map );
		}
		{ # section notes:
			my $map = $self->request_section_notes_map($unique_ids);
			$self->tt_params( request_section_notes_map => $map );
		}
        { # config override for non-default table cols:
            if ( my $yaml = $self->get_yaml_file('worklist_columns') ) {
                $self->tt_params( worklist_cols => $yaml );
            }
        }
		{ # callback for who requested test where test_type = test:
            if ( my $yaml = $self->get_yaml_file('requesting_user_sections') ) {
                $self->tt_params( requesting_user_sections => $yaml );
            }
			my $_self = $self; weaken $_self; # or get circular refs inside the callbacks
			my $user = sub { $_self->model('WorkList')->get_requesting_user(@_) };
			$self->tt_params( requesting_user => $user );
		}
	}

    my $vars = $self->query->Vars; # warn Dumper $vars;
    $vars->{display_format} ||= 'defined'; # or get 'uninitialized' warning in re
	{ # if it's a request for data entry, set tmpl flag, get lab users, rtn tt:
        my $is_data_entry =
            $vars->{results_entry} || $vars->{display_format} =~ /data entry/i;

        if ( $is_data_entry ) {
            my $user_list = $self->get_lab_staff_users;
            my $status_options
                = $self->_get_status_options_for_data_entry($lab_section_id);

            $self->tt_params(
                is_results_entry => 1,
                user_list => $user_list,
                status_options => $status_options,
            );
            $self->js_validation_profile('worklist_update_status');
            return $self->tt_process('worklist/data_entry.tt', $errs);
        }
    }
    # else return display format:
    return $self->tt_process();
}

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

	my $status_query = $self->query->param('status_query')
	|| return $self->forward('default');

    my $duration = $self->query->param('duration') # only used for status = unreported
        || $self->cfg('settings')->{unreported_duration};

    my %args = (
        status_query => $status_query,
        duration     => $duration,
    ); # warn Dumper \%args;
	my $data = $self->model('WorkList')->request_status_query(\%args);

	# return if no requests:
	if (! @$data ) {
		my $msg = $self->messages('worklist')->{no_outstanding_requests};
		$self->flash( info => $msg );
		return $self->redirect( $self->query->url . '/worklist' );
	}

	$self->tt_params( requests => $data );

	{ # get some data maps for tmpl:
		my @request_ids = map { $_->id } @$data;

		{ # specimens map:
			my $map = $self->specimen_map(\@request_ids);
			$self->tt_params( specimen_map => $map );
		}
		{ # request_options:
			my $map = $self->request_options_map(\@request_ids);
			$self->tt_params( request_options_map => $map );
		}
		{ # duration map:
			my $map = $self->time_duration_map($data);
			$self->tt_params( duration_map => $map );
		}
        # outstanding lab-tests:
        my @want_lab_tests = qw( incomplete unreported unauthorised );
        if ( grep $status_query eq $_, @want_lab_tests ) {
            my $o = $self->model('LabTest')
                ->get_request_lab_tests_status(\@request_ids); # warn Dumper $data;
            my %tests;
            for (@$o) {
                next if $_->status->description eq 'complete'; # skip
                my %t = (
                    section => $_->lab_test->lab_section->section_name,
                    test    => $_->lab_test->field_label,
                );
                push @{ $tests{$_->request_id} }, \%t;
            }
            $self->tt_params( incomplete_lab_tests => \%tests );
        }
	}

	return $self->render_view('worklist/status_query.tt'); # using firstname_format
}

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

	# need user_id & status_option_id:
    my $dfv = $self->check_rm('display', $self->validate('worklist_update_status') )
	|| return $self->dfv_error_page;

	my $data = $dfv->valid; # warn Dumper $data;

	# get list of request_lab_test.id's
	my @request_lab_test_ids = $self->query->param('request_lab_test_id');

	if (! @request_lab_test_ids) {
		$self->flash( warning => $self->messages('worklist')->{no_lab_test_ids} );
		my $option_id = $self->query->param('status_option_id'); # warn $option_id;
		my $url = $self->query->url . '/worklist/display/' . $self->param('id')
			# have to pass 'results_entry' flag in url:
			. "?results_entry=1;status_option_id=$option_id";
		return $self->redirect( $url );
	}

=begin # too complicated to do this	- using checkbox flag in tt now
	{ # require confirmation if using delete option:
		my $options_map
			= $self->model('Result')->lab_test_status_options_map; # warn Dumper $options_map;
		my $option_id = $data->{status_option_id};

		if ( $options_map->{$option_id}->{description} eq 'delete' ) {
			unless ( $self->query->param('confirm_delete') ) {
				$self->tt_params( confirm_required => 1 );
				return $self->forward('display'); # NEED SOME PARAMS
			}
		}
	} return 1;
=cut

	# add request_lab_test_ids to $data:
	$data->{request_lab_test_ids} = \@request_lab_test_ids;

	my $rtn = $self->model('Result')->update_lab_tests_from_worklist($data);

	$self->tt_params(
        updates => $rtn->{updates},  # arrayref
        failed  => $rtn->{failures}, # scalar ie record already deleted
    );

	{ # get some maps for worklist/updates.tt:
		my $users_map = $self->usernames_map;
		$self->tt_params( users_map => $users_map );

		my $status_options_map = $self->lab_test_status_options_map('id');
		$self->tt_params( status_options_map => $status_options_map );
	}

	if ( my $err = $rtn->{error} ) { # $self->debug($rtn);
		return $self->error($err);
	}
	elsif ($rtn->{success}) { # warn $rtn->{success};
		$self->flash( info => $self->messages('worklist')->{update_success} );
		return $self->tt_process('worklist/updates.tt');
	}
	elsif ($rtn->{failures}) { # warn $rtn->{failures}; # ie all failed
		$self->flash( warning => $self->messages('worklist')->{update_fails} );
		return $self->redirect( $self->query->param('query_params') ); # hidden fld
	}
	else { # no db error, but also no records updated (probably unlikely unless db->err):
		$self->flash( warning => $self->messages('worklist')->{update_failure} );
		return $self->redirect( $self->query->param('query_params') ); # hidden fld
	}
}

# ------------------------------------------------------------------------------
sub _get_status_options_for_data_entry {
	my ($self, $lab_section_id) = @_; $self->_debug_path();

	# get all status options (supply 'key'):
	my $all_status_options = $self->lab_test_status_options_map('description');

	my $section_status_options
		= $self->model('LabSection')->get_section_status_options($lab_section_id);

    my @options = map {
        {
            description => $_->status_option->description,
            id => $_->status_option_id,
        };
    } @$section_status_options;

	# need to add 'complete' & 'delete' to @options:
    push @options, (
        {
            description => 'complete',
            id => $all_status_options->{complete}->{id},
        },
        {
            description => 'delete',
            id => $all_status_options->{delete}->{id},
        },
    ); # warn Dumper \@options;
    return \@options;
=begin
	while ( my ($option, $data) = each %$all_status_options ) {
		next unless grep $option eq $_, qw(complete delete);
		$section_status_options->{$option} = $data->{id};
	}

	return $section_status_options;
=cut
}

1;
