package LIMS::Model::Roles::ResultsUpdate;

use Moose::Role;

# has history_params => ( is => 'ro', isa => 'HashRef', lazy_build => 1 ); # needs to handle loops
has request_status_options_map => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );

use Data::Dumper;

#-------------------------------------------------------------------------------
sub do_results_summary_update {
    my $self = shift;
    
    my $history_params = $self->history_params; # warn Dumper $history_params;
    my $form_data      = $self->form_data; # warn Dumper $form_data;
    
    # get current result_summary for this request & section:
    my $request_results_summary = $self->_get_results_summary();    

    # 'results_summary' is textbox, '_results_summary' is drop_down 
    # join _results_summary (if exists) onto end of results_summary (if exists):
    my $form_input = join '; ', map $form_data->{$_}, grep $form_data->{$_},
        qw(results_summary _results_summary); # warn $form_input; 
        
    my $results_summary = ''; # maybe set below
  
    # return if results_summary exists & no change:
    if  ($results_summary = $request_results_summary->results_summary) { 
        no warnings 'uninitialized';
        return if $results_summary eq $form_input;
    }

    # if existing results_summary, and/or form submission containing results_summary:
    if ( $results_summary || $form_input ) { 
       my $section_name = $form_data->{_section_name};
        
        # if $form_input, do insert/update, else delete:
        if ($form_input) {
            # if results_summary already exists, update, else new:
            $history_params->{action} = $request_results_summary->results_summary
                ? "updated $section_name result summary"
                : "new $section_name result summary";
            # update result_summary:   
            $request_results_summary->results_summary($form_input);
            $request_results_summary->insert_or_update;            
 
            LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;                
        }
        else { # delete:
            $request_results_summary->delete;
            $history_params->{action} = "deleted $section_name result summary";
            LIMS::DB::RequestLabTestHistory->new(%$history_params)->save; 
        }
    }
}

#-------------------------------------------------------------------------------
sub do_section_notes_update {
    my $self = shift;
    
    my $history_params = $self->history_params;
    my $form_data      = $self->form_data; # $self->debug($form_data);
    
    # get current notes for this request & section:
    my $request_section_notes = $self->_get_section_notes();
    
    # return if no difference:
    if ($request_section_notes) {
        no warnings 'uninitialized';
        return if $request_section_notes->details eq $form_data->{section_notes};
    }
    
    # if existing section notes, and/or form submission containing section notes:
    if ( $request_section_notes || $form_data->{section_notes} ) { 
        my %args = (
            request_id     => $form_data->{_request_id},
            lab_section_id => $form_data->{_section_id},
        );            
        my $o = LIMS::DB::RequestLabSectionNote->new(%args);
        
        my $section_name = $form_data->{_section_name};
        
        # if $form_input, do insert/update, else delete:
        if (my $form_input = $form_data->{section_notes}) {
            $o->details($form_input);
            $o->insert_or_update;
            
            $history_params->{action} = $request_section_notes ?
                "updated $section_name section notes"
                    : "new $section_name section notes";
 
            LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;                
        }
        else {
            $o->delete;
            $history_params->{action} = "deleted $section_name section notes";
            LIMS::DB::RequestLabTestHistory->new(%$history_params)->save; 
        }
    }
}

#-------------------------------------------------------------------------------
sub do_foreign_id_update {
	my $self = shift;

	my $history_params = $self->history_params;
	my $form_data      = $self->form_data; # $self->debug($form_data);

	# get current foreign id for this request & section:
	my $remote_system_id = $self->_get_remote_system_id();

	# return if no difference:
	if ($remote_system_id) {
		no warnings 'uninitialized';
		return if $remote_system_id->foreign_id eq $form_data->{foreign_id};
	}

	# if existing remote_system_id, and/or form submission containing foreign id:
	if ( $remote_system_id || $form_data->{foreign_id} ) {
		my %args = (
			lab_section_id => $form_data->{_section_id},
			request_id     => $form_data->{_request_id},
		);

		my $o = LIMS::DB::RequestLabSectionForeignID->new(%args);

		my $section_name = $form_data->{_section_name};

		# if $form_input, do insert/update, else delete:
		if ( my $form_input = $form_data->{foreign_id} ) {
			$o->foreign_id($form_input);
			$o->insert_or_update;

			$history_params->{action} = $remote_system_id
				? "updated $section_name remote system ID"
				: "new $section_name remote system ID";          

			LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;
		}
		else {
			$o->delete;
			$history_params->{action} = "deleted $section_name remote system ID";

			LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;
		}
	}
}

#-------------------------------------------------------------------------------
# request new lab_test or lab_investigation (uses same form param 'test_id'):
sub do_new_lab_investigation {
    my ($self, $test_id) = @_;

    my $history_params = $self->history_params;
    
    my $test = LIMS::DB::LabTest->new(id => $test_id)->load;

    my $status_option_new
        = LIMS::DB::LabTestStatusOption->new(description => 'new')->load;

    my %params = (
        lab_test_id => $test_id,
        request_id  => $self->form_data->{_request_id},
    );

    # create new request_lab_test object:
    my $request_lab_test = LIMS::DB::RequestLabTestStatus->new(%params);

    my $action = '';
    # load row (if exists):
    if ( $request_lab_test->load(speculative => 1) ) {
        # return if lab_test status already 'new':
        return if $request_lab_test->status_option_id == $status_option_new->id;
        $action = 're-requested';
    }
    else {
        $action = 'requested';
    }
    
    # update status_option_id & user_id:
    $request_lab_test->status_option_id($status_option_new->id);
    $request_lab_test->user_id($self->user_profile->{id});

    # insert or update object, update history on success:
    if ( $request_lab_test->save(changes_only => 1) ) {
        $history_params->{action} = $action . ' ' . $test->field_label;
        LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;
    }
}

#-------------------------------------------------------------------------------
sub do_complete_all_tests {
    my $self = shift;
    
    my $history_params = $self->history_params;
    my $form_data      = $self->form_data; # $self->debug($form_data);
    
    my $status_option
        = LIMS::DB::LabTestStatusOption->new(description => 'complete')->load;

    # can't use require_objects in update_products, so have to do it in 2 stages:
    my %args = (
        query => [ lab_section_id => $form_data->{_section_id} ],
    );
    my $section_lab_tests = LIMS::DB::LabTest::Manager->get_lab_tests(%args);    
    my @lab_test_ids = map $_->id, @$section_lab_tests;

    my $num_rows_updated = LIMS::DB::RequestLabTestStatus::Manager
        ->update_request_lab_test_status(
            set => {
                user_id          => $self->user_profile->{id},
                status_option_id => $status_option->id,
            },
            where => [
                request_id  => $self->form_data->{_request_id},
                lab_test_id => \@lab_test_ids,
                status_option_id => { ne => $status_option->id }
            ],
        ); # warn $num_rows_updated;
        
    $history_params->{action}
        = "set $form_data->{_section_name} section tests status to complete";
    LIMS::DB::RequestLabTestHistory->new(%$history_params)->save;
}

#-------------------------------------------------------------------------------
# revert request status from complete to reported/authorised:
sub do_request_status_check {
    my $self = shift;
    
    my $request_id = $self->form_data->{_request_id};
    
    # get map of request status options:
    my $status_option = $self->request_status_options_map; # warn Dumper $status_option;
    
    my $request = LIMS::DB::Request->new(id => $request_id)->load;
    
    # only interested if request status is complete:
    return if $request->status_option_id != $status_option->{complete}->{id};
    
    # revert request status to reported/authorised:
    my $new_status = $status_option->{authorised}->{is_active} eq 'yes'
        ? $status_option->{authorised}->{id}
        : $status_option->{reported}->{id};
        
    $request->status_option_id($new_status);
    $request->save;
}

#-------------------------------------------------------------------------------
sub history_params { # was a lazy_build, but now needs to cope with loops
    my $self = shift;
    
    my %params = (
        request_id => $self->form_data->{_request_id},
        user_id    => $self->user_profile->{id},
    );
    
    return \%params;
}

#-------------------------------------------------------------------------------
sub _build_request_status_options_map {
	my $self = shift;
	
	my $o = LIMS::DB::StatusOption::Manager->get_status_options;
	
	my %map = map {
		$_->description => $_->as_tree;
	} @$o;
	
	return \%map;
}

#-------------------------------------------------------------------------------
sub _get_results_summary {
    my $self = shift;
    
    my %args = (
        request_id => $self->form_data->{_request_id},
        section_id => $self->form_data->{_section_id},
    );
	# use existing M::Result method:
    my $results_summary = $self->get_request_results_summary(\%args);
	return $results_summary;
}

#-------------------------------------------------------------------------------
sub _get_section_notes {
    my $self = shift;
    
    my %args = (
        request_id     => $self->form_data->{_request_id},
        lab_section_id => $self->form_data->{_section_id},
    );

    my $section_notes
        = LIMS::DB::RequestLabSectionNote->new(%args)->load(speculative => 1);
    
    return $section_notes;
}

#-------------------------------------------------------------------------------
sub _get_remote_system_id {
	my $self = shift;

	my %args = (
		lab_section_id => $self->form_data->{_section_id},
		request_id     => $self->form_data->{_request_id},	
    );

	my $remote_system_id
		= LIMS::DB::RequestLabSectionForeignID->new(%args)->load(speculative => 1);

	return $remote_system_id;
}
 
1;