package LIMS::Model::WorkList;

use Moose;
extends 'LIMS::Model::Base';
    with (
        'LIMS::Model::Roles::SessionData', # provides $self->user_profile
    );
use namespace::clean -except => 'meta';

has lab_test_status_options_map => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has form_data => ( is => 'rw', isa => 'HashRef', default => sub { {} } );

__PACKAGE__->meta->make_immutable;

use Data::Dumper;

#-------------------------------------------------------------------------------
sub get_outstanding_investigations {
    my $self = shift;
    my $data = shift; # warn Dumper $data;

    my %query_params = ();

    # restrict on optional lab_test_id if supplied:
    if ( my $lab_test_id = $data->{lab_test_id} ) {
        $query_params{lab_test_id} = $lab_test_id; # str or arrayref
    }
	else {
		$query_params{'lab_test.lab_section_id'} = $data->{lab_section_id};
	}
	
	# restrict on optional status_option_id if supplied:
	if ( my $status_option_id = $data->{status_option_id} ) {
		$query_params{status_option_id} = $status_option_id; # str
	}
	# need to exclude 'complete' if status_option_id not supplied:
	else {
		# get lab_test_status_option.id for 'complete':
		my $complete_id = $self->lab_test_status_options_map->{complete};
		$query_params{status_option_id} = { ne => $complete_id };			
	}    
    
	my %sort_options = (
		lab_number => [ qw(requests.year requests.request_number) ],
		lab_tests  => [
			qw(
				lab_test.test_type
				lab_test.field_label
				requests.year
				requests.request_number
			)
		],
	);
	
	# if sort_by supplied, use it:
	my $sort_by = $data->{sort_by} || 'lab_number'; # default if not supplied
	
	my %args = (
		query => [ %query_params ],
		require_objects => [
            'request.patient_case.patient',
            'request.patient_case.referral_source',
            'lab_test.lab_section',
            'status',
        ],
		with_objects => [
            'request.request_initial_screen.screen',
		],
        nested_joins => 0, # THIS IS ESSENTIAL FOR EFFICIENT QUERY (ie 138 vs > 16 x 10^9 rows !!)
        sort_by => $sort_options{$sort_by},
	);

	# restrict db hit if only want selected table(s):
	if ( my $selected_tables = $data->{fetch_only} ) {
		$args{fetch_only} = $selected_tables;
	}
	
#$self->set_rose_debug(1);
    my $outstanding_investigations = LIMS::DB::RequestLabTestStatus::Manager
        ->get_request_lab_test_status(%args);
#$self->set_rose_debug(0);

    return $outstanding_investigations;
}

#-------------------------------------------------------------------------------
sub get_active_sections_list {
    my $self = shift;
    
    my $complete_id = $self->lab_test_status_options_map->{complete};
    
    my %args = (
        query => [ status_option_id => { ne => $complete_id } ],
        require_objects => 'lab_tests.request_lab_test_status',
        multi_many_ok   => 1, # to silence warning
        sort_by  => 'section_name',
        distinct => 1,
    );
    
    my $active_sections = LIMS::DB::LabSection::Manager->get_lab_sections(%args);
    
    return $active_sections;
}

#-------------------------------------------------------------------------------
sub get_active_investigations_for_section { 
    my ($self, $lab_section_id) = @_;
    
    my $complete_id = $self->lab_test_status_options_map->{complete};

    my %args = (
        query => [
            lab_section_id   => $lab_section_id,
            status_option_id => { ne => $complete_id },
        ],
        require_objects => [ 'lab_section', 'request_lab_test_status' ],
        sort_by  => 'field_label',
        distinct => 1,
    );
    
    my $investigations = LIMS::DB::LabTest::Manager->get_lab_tests(%args);
    
    return $investigations;
}

#-------------------------------------------------------------------------------
sub request_status_query {
    my $self   = shift;
    my $status = shift;
    
    my $data = []; # caller expects arrayref returned 
    
#$self->set_rose_debug(1);    
    my $args = $self->_get_request_status_query_args($status); # $self->debug($args);

    if ($args) {
        $data = LIMS::DB::Request::Manager->get_requests(%$args);
    }
#$self->set_rose_debug(0);

    return $data;
}

#-------------------------------------------------------------------------------
sub _get_request_status_query_args {
    my $self   = shift;
    my $status = shift;
    
    # args common to all status requests:
    my %args = (
        query => undef, # defined below
        require_objects => [
			'status_option',
            'patient_case.patient',
            'patient_case.referral_source',
        ],
        with_objects => [ ], # maybe defined below
        nested_joins => 0, 
        sort_by => [ 'requests.created_at, request_number' ],
    );
    
    if ($status eq 'urgent') {
        push @{ $args{require_objects} }, 'request_option.option';
        push @{ $args{with_objects}    }, 'request_initial_screen.screen';
		
		# only want unreported/unauthorised requests:
		my @status_options = qw(new screened);
		
		# add 'reported' to status_options if 'authorised' option in use:
		my $option_authorised
			= LIMS::DB::StatusOption->new(description => 'authorised')->load;		
		push @status_options, 'reported' if $option_authorised->is_active eq 'yes';

        $args{query} = [
            option_name => 'urgent',
			'status_option.description' => \@status_options,
        ],
    }
	
=begin # using status_option_id now
    else {
        my $requests;
        
        if ($status eq 'unscreened') {
            # get request objects not in request_initial_screen table:
            $requests = LIMS::DB::Request::Manager->get_requests(
                query => [
                    request_id => { eq => undef },
                ],
                with_objects => 'request_initial_screen',
            );
        }
        elsif ($status eq 'unreported') { 
            # get request objects not in request_report table:
            $requests = LIMS::DB::Request::Manager->get_requests(
                query => [
                    request_id => { eq => undef },
                    created_at => { lt => DateTime->today->subtract(days => 7) },
                ],
                with_objects => 'request_report',
            );
            push @{ $args{require_objects} }, 'request_initial_screen.screen';
        }

        # get list of request_id's to pass to query, or return if empty:
        my @ids = map { $_->id } @$requests or return 0; # use 'or' not '||'
        
        $args{query} = [ id => \@ids ]; # warn Dumper \@ids;
    } # warn Dumper \%args; 
=cut
	else {
        if ($status eq 'unscreened') {
			$args{query} = [ 'status_option.description' => 'new' ],
		}
        elsif ($status eq 'unreported') { 
			$args{query} = [
				'status_option.description' => 'screened',
                created_at => { lt => DateTime->today->subtract(days => 7) },
			],
			push @{ $args{require_objects} }, 'request_initial_screen.screen';
		}
		# only supplied by template if 'authorised' status_option is active:
        elsif ($status eq 'unauthorised') {
			$args{query} = [ 'status_option.description' => 'reported' ],
			push @{ $args{require_objects} }, 'request_initial_screen.screen';
		}
		elsif ($status eq 'incomplete') {
			my $option_authorised
				= LIMS::DB::StatusOption->new(description => 'authorised')->load;

			my $status = $option_authorised->is_active eq 'yes'
				? 'authorised'
				: 'reported';
				
			$args{query} = [ 'status_option.description' => $status ],
			push @{ $args{require_objects} }, 'request_initial_screen.screen';			
		}
		else { # should never happen, but will return all records otherwise:
			$args{query} = [ request_number => 0 ],
		}
	} # warn Dumper \%args; 
	
    return \%args;
}

#-------------------------------------------------------------------------------
sub _build_lab_test_status_options_map {
    my $self = shift;
    
    my $status_options = LIMS::DB::LabTestStatusOption::Manager->
        get_lab_test_status_options;
        
    my %map = map {
        $_->description => $_->id;
    } @$status_options;
    
    return \%map;
}

1;
