package LIMS::Controller::Search;

use base 'LIMS::Base';

use Moose;
	with (
		'LIMS::Controller::Roles::History',
		'LIMS::Controller::Roles::DataMap',
		'LIMS::Controller::Roles::RecordHandler',
		'LIMS::Controller::Roles::ResultHandler',
		'LIMS::Controller::Roles::SearchConstraint', # generate_search_constraints()
	);
__PACKAGE__->meta->make_immutable(inline_constructor => 0);

use Data::Dumper;

# can't use __PACKAGE__->authz->authz_runmodes() - crashes on non-logged-in user

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

	return $self->forbidden() unless $self->user_can('search');

    my $trials = $self->model('ClinicalTrial')->get_trials;

    $self->tt_params( trials => $trials );

   	return $self->render_view($self->tt_template_name, $errs);
}

#-------------------------------------------------------------------------------
# recieves url for a single record, by request.id:
sub load : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);
	return $self->forbidden() unless $self->user_can('search');

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

    return $self->_get_single_record($id);
}

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

	return $self->forbidden() unless $self->user_can('search');

	my $dfv = $self->check_rm('default', $self->validate('search') )
	|| return $self->dfv_error_page;

    my $data = $dfv->valid; # $self->debug($data);

    my $search_constraints = $self->generate_search_constraints($data)
    || return $self->forward('default'); # protect against submission of empty form
        # $self->debug($search_constraints);

	# how many records match submitted search params:
    my $requests_count = $self->model('Request')
		->search_requests_count($search_constraints); # $self->debug($requests_count);

	# stash requests_count for possible use later (eg _get_multiple_records):
	$self->stash( requests_count => $requests_count );

    # zero hits, or too many to handle:
    if (! $requests_count || $requests_count > 1000 ) {
        $self->stash->{status_msg} = $requests_count ?
            sprintf $self->messages('search')->{too_many_records}, $requests_count
                : $self->messages('search')->{no_records_found};

        my $html = $self->forward('default');
        return $self->fill_form($html);
    }

    # if we only have 1 record, get request.id & pass to _get_single_record():
    elsif ($requests_count == 1) {
		my $request_id
			= $self->model('Request')->get_request_id($search_constraints);
        return $request_id
            ? $self->_get_single_record($request_id)
            : $self->error('no request_id returned from model');
    }

	# have between 2 & 1000 records
	else {
		return $self->_get_multiple_records($search_constraints);
	}
}

#-------------------------------------------------------------------------------
sub deleted_record : Runmode {
	my $self = shift; $self->_debug_path();
	
	if ( my %vars = $self->query->Vars ) { # warn Dumper \%vars;
		return $self->redirect( $self->query->url . '/search/deleted_record' )
			unless grep $vars{$_}, qw( first_name last_name hmds_ref );		
		
		my $data = $self->model('History')->get_deleted_records(\%vars); # warn Dumper $data;
		if (! @$data) {
			$self->flash(info => $self->messages('search')->{no_records_found});
		}
		
		$self->tt_params( result => $data );
	}	
	return $self->tt_process;
}

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

	my $q = $self->query;

	my %args_for_search = do {
		my @params = ( $q->param('sort_by') );
		push @params, uc $q->param('sort_order') if $q->param('sort_order');
		sort_by => join ' ', @params;
	}; # warn Dumper \%args_for_search;

	# retrieve requests_count from do_search():
	my $requests_count   = $self->stash->{requests_count};
	# entries per page from form or use config default:
	my $entries_per_page = $q->param('entries_per_page')
	|| $self->cfg('settings')->{entries_per_page}; # warn $entries_per_page;

	# if > 10, invoke pager for template and add limit & offset params to \%args:
	if ( $requests_count > $entries_per_page ) {
		$self->pager({ query => \%args_for_search, total => $requests_count });
	}  #  $self->debug(\%args_for_search);

	{ # get record & specimens map data structures into tt_params:
		my %local_args = (
			search_constraints => $search_constraints,
			args_for_search    => \%args_for_search,
		); # warn Dumper \%local_args;

		# get records matching search_contraints + args_for_search:
		my $records	= $self->model('Request')->find_requests(\%local_args);

		# get specimen_map for all requests so we have 1 db hit not 1 per request:
		my @request_ids = map { $_->id } @$records;
		my $specimen_map = $self->specimen_map(\@request_ids);

		$self->tt_params(
			records      => $records,
			specimen_map => $specimen_map,
		);
	}

	# get request_histories for all requests so we have 1 db hit not 1 per request:
   	# my $history_map = $self->get_request_histories($records); # using 'requests.created_at' now

    $self->tt_params( total_count => $requests_count );

	# send template through render_view() to apply symbolise() function:
    return $self->render_view('search/multiple_records.tt');
}

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

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

    # functions transferred to LIMS::Controller::Roles::RecordHandler
    my $request_data = $self->get_single_request_data($request_id)
	|| return $self->error("request_id '$request_id' does not exist");

    # format lab_test data for template:
    $self->format_raw_lab_test_data($request_data);
	$self->process_raw_lab_test_data($request_data);

	# log event:
	$self->history_log_event({ request_id => $request_id, event => 'view' });

    # using render_view() for access to join_hash_values:
    return $self->render_view('record/default.tt', $request_data);
}

1;
