package LIMS::Controller::Register;

use Moose;
BEGIN { extends 'LIMS::Base'; }
with (
    'LIMS::Controller::Roles::Misc', 
);
__PACKAGE__->meta->make_immutable(inline_constructor => 0);

use LIMS::Local::Utils;
use Data::Dumper;

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

	return $self->forbidden() unless $self->user_can('register');
	
    # TODO: js_validation doesn't work with 'require_some'
    $self->js_validation_profile('patient_search_data');

    return $self->tt_process($errs);
}

#-------------------------------------------------------------------------------
sub online_request_form : Runmode {
    my $self = shift; $self->_debug_path($self->get_current_runmode);
    
	return $self->forbidden() unless $self->user_can('register');

    my $id = $self->query->param('id') || return $self->forward('default');
    
    my $data = $self->model('Request')->get_request_form($id); # warn Dumper $data;
    unless ($data) { # probably incorrectly hand-typed barcode string
		my $msg = $self->messages('registration')->{no_request_form_id};
		$self->flash( warning => $msg );	
        return $self->redirect( $self->query->url . '/register' );
    }
    
    my $name = sprintf '%s, %s', $data->last_name, $data->first_name;

    # put nhs_number & name into query params in format expected by patient_search():
    my %vars = ( patient_no => $data->nhs_number, name => $name ); # warn Dumper \%vars;
    $self->query->param( $_ => $vars{$_} ) for keys %vars;

    # get output from patient_search() but don't return view yet:
    my $template = $self->forward('patient_search'); # uses patient_no & name

    # add rest of vars from online request form & redo _extract_params_from_request()
    # in case patient not found in patient_search() - populates tt form with params:
    $vars{$_} = $data->{$_} for qw(location_name location_id gender);
    $vars{$_} = $data->dob->$_ for qw(year month day);
    $vars{unit_number} = $data->patient_number;
    $self->_extract_params_from_request(\%vars); # $self->debug($vars);

    # update request_form.imported col:
    $self->model('Request')->request_form_import($id);
    
    # now return template processed in patient_search():
    return $template;
}

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

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

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

    # need form params in scalar (hashref) context:
    my $form_params = $dfv->valid; # $self->debug('form_params:'); # $self->debug($form_params);

    # parse valid form params (extract last_name, first_name, dob, nhs_number, unit_number):
    my $vars = $self->_extract_params_from_request($form_params); # $self->debug($vars);

    # get search params as arrayref for query, or redisplay search page:
    my $search_param = $self->_generate_search_constraints($vars)
    || return $self->forward('default'); # $self->debug($search_param);

    # format search terms as a string for display in template:
    my $search_terms = $self->_convert_search_terms_for_display($vars);

    my %args_for_search = ( query => $search_param ); # $self->debug(\%args_for_search);

    my $patient_matches_count
		= $self->model('Patient')->patient_matches_count(\%args_for_search);
    # $self->debug([$patient_matches_count]);

    if (! $patient_matches_count ) {
		my $msg = sprintf $self->messages('registration')->{no_records_found},
			$search_terms;
		$self->flash( info => $msg );	
        return $self->redirect( $self->query->url . '/patient' );
    }

	# override cfg.settings.entries_per_page for this search:
	$self->cfg('settings')->{entries_per_page} = 50;

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

    # do search for previous patients:
    my $patient_cases
		= $self->model('PatientCase')->registration_search(\%args_for_search);

	my $results = $self->extract_patients_and_locations($patient_cases);

    $self->tt_params(
        total_count  => $patient_matches_count,
        search_term  => $search_terms,
        results      => $results, 
    );

    return $self->render_view('register/select_patient.tt');
}

#-------------------------------------------------------------------------------
sub _convert_search_terms_for_display {
    my $self = shift; $self->get_current_runmode;
    my $vars = shift || return;

    # convert DT object back to EU date string for template:
    if ( my $dob = $vars->{dob} ) {
        $vars->{dob} = $dob->dmy; # dd-mm-yyyy format
    }

    my $search_terms = join ' & ',
        map { sprintf '%s=%s', $_, $vars->{$_} }
             grep { $vars->{$_} } qw(name dob patient_no);

    return $search_terms;
}

#-------------------------------------------------------------------------------
sub _extract_params_from_request {
    my $self  = shift; $self->_debug_path();
    my $param = shift; # $self->debug($param);

    if ( my $name = $param->{name} ) {
        my ($last_name, $first_name) = split /\,\s?/, $name;

        $param->{last_name}  = $last_name;
        $param->{first_name} = $first_name || undef;
		
		# put last_name & first_name into query param for patient merge link:
		$self->query->param( last_name  => $last_name );
		$self->query->param( first_name => $first_name );
    }

    if ( my $patient_no = $param->{patient_no} ) { # DEBUG 'patient_no:' .$patient_no;
        LIMS::Local::Utils::check_nhsno( $patient_no ) # if $patient_no passes nhs_no validation:
            ? $param->{nhs_number}  = $patient_no
            : $param->{unit_number} = $patient_no;
    }

    if ( grep $param->{$_}, qw(day month year) ) {
        # create dob as DT object:
        my $dob = DateTime->new( map { $_ => $param->{$_} } qw(day month year) ); # $self->debug($dob);
        $param->{dob} = $dob;
    } # warn Dumper $param;

    # save extracted search params in session for retrieval if redirected to /patient (if no records found):
    $self->session->param( patient_search_params => $param );

    return $param;
}

#-------------------------------------------------------------------------------
sub _generate_search_constraints {
    my $self  = shift; $self->_debug_path();
    my $param = shift; # $self->debug($param);

    my %search;

    my @form_fields = qw(patient_id last_name first_name dob unit_number nhs_number); # DEBUG $form_fields;

    my @search_keys = grep $param->{$_}, @form_fields; # $self->debug(\@search_keys);

    @search{@search_keys} = map {
        /_name/ ?
            { like => $param->{$_} . '%' } : # create 'like' query
            $param->{$_}; # create regular query
        } @search_keys; # $self->debug(\%search);

    if (%search) {
        return [ %search ]; # query needs arrayref
    }
    else {
        $self->stash->{error_msg}
			= $self->messages('registration')->{empty_submission};
        return 0;
    }
}

=begin
sub _group_cases_by_patient {
	my $self = shift;
	my $iterator = shift;

	my %patients;

	CASE:
	while (my $case = $iterator->next) {
		my $id = $case->patient->id; # $self->debug($id);

		# add referral_source object:
		push @{ $patients{$id}{referral_source} }, $case;

		# only need details once per patient:
		next CASE if $patients{$id}{details};

		my %details = (
			last_name   => $case->patient->last_name,
			first_name  => $case->patient->first_name,
			middle_name => $case->patient->middle_name,
			nhs_number  => $case->patient->nhs_number,
			gender      => $case->patient->gender,
			dob         => $case->patient->dob,
			id		    => $case->patient->id,
		);
		$patients{$id}{details} = \%details;
	}

	my @patients;

	sub by_name {
		$patients{$a}{details}{last_name}   cmp $patients{$b}{details}{last_name}
		  ||
		$patients{$a}{details}{first_name}  cmp $patients{$b}{details}{first_name}
		  ||
		$patients{$a}{details}{middle_name} cmp $patients{$b}{details}{middle_name};
	}

	foreach ( sort by_name keys %patients ) { # $self->debug($patients{$_}{referral_source});
		push @patients, {
			details => $patients{$_}{details},
			referral_source => $patients{$_}{referral_source},
		};
	}

	return \@patients;
}
=cut

1;
