package LIMS::Model::ReferralSource;

use strict;
use warnings;

use base 'LIMS::Model::Base';
use LIMS::Local::Utils;

# ------------------------------------------------------------------------------
# returns hashref of sources, with keys = location_type
sub get_referral_sources_by_type {
    my $self = shift;

    my %args = (
        require_objects => 'referral_type',
        sort_by => 'display_name',
    );

    # get all referral_sources rows as arrayref:
    my $src = LIMS::DB::ReferralSource::Manager->get_referral_sources_iterator(%args);

    my (@hospitals, @practices);

    while (my $source = $src->next) {
        if ( $source->referral_type->description eq 'hospital' ) {
            push @hospitals, $source;
        }
        elsif ( $source->referral_type->description eq 'practice' ) {
            push @practices, $source;
        }
    }

    return {
        hospitals => \@hospitals,
        practices => \@practices,
    }
}

# ------------------------------------------------------------------------------
sub get_referral_sources_count {
    my ($self, $search_terms) = @_; # $self->debug($search_terms);
    
    my %args = (
        query => [ %$search_terms ],
    );
    
    my $total
        = LIMS::DB::ReferralSource::Manager->get_referral_sources_count(%args);
        
    return $total;
}

# ------------------------------------------------------------------------------
sub get_parent_organisations_count {
    my ($self, $search_terms) = @_; # $self->debug($search_terms);
    
    my %args = (
        query => [ %$search_terms ],
    );
    
    my $total = LIMS::DB::ParentOrganisation::Manager
        ->get_parent_organisations_count(%args);
        
    return $total;
}

# ------------------------------------------------------------------------------
sub get_referral_sources {
    my $self = shift;
    my ($search_terms, $args) = @_; # $self->debug($args);

    $args->{query} = [ %$search_terms ];
    $args->{require_objects} =  [ qw(referral_type parent_organisation) ];
    
    my $sources = LIMS::DB::ReferralSource::Manager->get_referral_sources(%$args);

    return $sources;
}

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

    my $referral_types
        = LIMS::DB::ReferralType::Manager->get_referral_types();

    return $referral_types;
}

# ------------------------------------------------------------------------------
sub get_referral_source {
    my $self   = shift;
    my $src_id = shift;

    my $source = LIMS::DB::ReferralSource->new(id => $src_id)
        ->load( with => 'referral_type' );

    return $source;
}

# ------------------------------------------------------------------------------
sub get_parent_organisations {
    my $self = shift;
    my ($search_terms, $args) = @_;
    
    $args->{query} = [ %$search_terms ];
    $args->{require_objects} = ['referral_type'];
    
#$self->set_rose_debug(1);    
    my $parent_organisations
        = LIMS::DB::ParentOrganisation::Manager->get_parent_organisations(%$args);
#$self->set_rose_debug(0);    
    return $parent_organisations;    
}

# ------------------------------------------------------------------------------
sub get_email_contacts {
	my $self = shift;
	
	my %args = (
		sort_by => 'display_name',
		require_objects => 'referral_source',
	);
	
	my $contacts = LIMS::DB::EmailContact::Manager->get_email_contacts(%args);

	return $contacts;
}

# ------------------------------------------------------------------------------
sub get_email_contact {
	my ($self, $id) = @_;
	
	my $contact = LIMS::DB::EmailContact->new(id => $id)->load;
	
	return $contact;
}

# ------------------------------------------------------------------------------
sub update_email_contacts {
	my ($self, $data) = @_; 
	
    my %args = ( class => 'EmailContact', data  => $data );

    return $self->update_object(\%args);
}

# ------------------------------------------------------------------------------
# get active mdt contacts: 
sub get_mdt_email_contacts {
	my $self = shift;
	
	my $all_contacts = $self->get_email_contacts;
	
	my @mdt_contacts = grep {
		$_->type eq 'mdt' && $_->is_active eq 'yes';
	} @$all_contacts;

	return \@mdt_contacts;
}

# ------------------------------------------------------------------------------
sub has_mdt_contact {
	my ($self, $ref_src_id) = @_; # warn $ref_src_id;
	
	# get parent_organisation for $referral_source_id:
	my $ref_src = LIMS::DB::ReferralSource->new(id => $ref_src_id)->load;
	my $parent_org_id = $ref_src->parent_organisation_id;
	
	my %args = (
		query => [ type => 'mdt' ],
		require_objects => 'referral_source',
	);
	
	my $contacts = LIMS::DB::EmailContact::Manager->get_email_contacts(%args);
	
	for (@$contacts) {
		if ( $_->scope eq 'hospital' ) {
			# if contact for a hospital, return true its ref_src_id matches:
			return 1 if $_->referral_source_id == $ref_src_id;
		}
		elsif ( $_->scope eq 'organisation' ) {
			# need to see if its parent_organisation matches:
			return 1 if
				$_->referral_source->parent_organisation_id == $parent_org_id;			
		}
	}
	# if we get here, there's no mdt contact:
	return 0;
}

# ------------------------------------------------------------------------------
sub get_parent_organisation {
    my $self   = shift;
    my $org_id = shift;
    
    my $parent_organisation = LIMS::DB::ParentOrganisation
        ->new(id => $org_id)->load(with => 'referral_type');
        
    return $parent_organisation;    
}

# ------------------------------------------------------------------------------
sub update_referral_sources {
    my $self = shift;
    my $data = shift; # $self->debug($data);
    
	# update method different for hospitals & (new) practices:
    my $rtn_value =
        # if it's a *new* practice:
        $data->{referral_type} eq 'practice' && ! $data->{id} ?
            $self->_new_practice($data) :
                # else hospital or edit practice:
                $self->_update_referral_source($data) ; 
    
    return $rtn_value;
}

# ------------------------------------------------------------------------------
sub update_parent_organisations {
    my $self = shift;
    my $data = shift;
    
#$self->set_rose_debug(1);
    my $parent_organisation = LIMS::DB::ParentOrganisation->new();

    my %args = (
        data => $data,
        obj  => $parent_organisation,
    );
    
    # get form_params for referral_sources table into $referral_source object:
    $self->populate_object_with_form_data(\%args);

    # get referral_type data:
    my $referral_type
        = LIMS::DB::ReferralType->new(description => $data->{referral_type})->load;

    # add referral_type object to referral_source object:
    $parent_organisation->referral_type($referral_type);
    
    eval {
        $parent_organisation->insert_or_update;
    };
#$self->set_rose_debug(0);

    return $@ if $@;
}

# ------------------------------------------------------------------------------
sub update_network_locations {
	my ($self, $parent_ids) = @_;
	
    my $db = $self->lims_db; # ie LIMS::DB->new_or_cached;
    
    my $update = sub {
		# 1st clear table:
		LIMS::DB::LocalNetworkLocation::Manager
			->delete_local_network_locations(all => 1); # or it refuses!!
		# add new data (if any):
		map {
			LIMS::DB::LocalNetworkLocation->new(parent_id => $_)->save;
		} @$parent_ids;
	};
	
    my $ok = $db->do_transaction($update);

    return $ok ? 0 : 'update_network_locations() error - ' . $db->error;
}

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

#$self->set_rose_debug(1);    
    my $referral_source = LIMS::DB::ReferralSource->new();
    
    my %args = (
        data => $data,
        obj  => $referral_source,
    );
    
    # get form_params for referral_sources table into $referral_source object:
    $self->populate_object_with_form_data(\%args);
    
    # get referral_type data:
    my $referral_type
        = LIMS::DB::ReferralType->new(description => $data->{referral_type})->load;

    # add referral_type object to referral_source object:
    $referral_source->referral_type($referral_type);
    
    eval {
        $referral_source->insert_or_update;
    };
#$self->set_rose_debug(0);

    return $@ if $@;
}

# ------------------------------------------------------------------------------
sub _new_practice { 
    my $self = shift;
    my $data = shift; # $self->debug( $data);

    # massage data into format required by referral_sources & parent_organisation tables:
    $self->_format_data_for_practices($data); # warn Dumper $data;
    
    # parent_organisation.parent_code & referrral_sources.organisation_code
    # same thing for practice:
    $data->{parent_code} = $data->{organisation_code};
    
    my $db = $self->lims_db; # ie LIMS::DB->new_or_cached;
    
    my $new_practice = sub {
		my $parent_organisation = LIMS::DB::ParentOrganisation->new();
        my $referral_source     = LIMS::DB::ReferralSource->new();
		
        # if parent_practice_id supplied (ie new practice is a branch):
		if ( my $id = $data->{parent_practice_id} ) {
			$data->{parent_organisation_id} = $id;
		}
		else { # create new parent_organisation for practice:
			my %args = (
				data => $data,
				obj  => $parent_organisation,
			);
			# get form_params for parent_organisation table into $parent_organisation object:
			$self->populate_object_with_form_data(\%args);            

			# add parent_organisation object to referral_source object:
			$referral_source->parent_organisation($parent_organisation);
		}

        { # populate $referral_source object:
            my %args = (
                data => $data,
                obj  => $referral_source,
            );
            $self->populate_object_with_form_data(\%args);
        }
		# save new practice (+ parent if required):
        $referral_source->save;
    };

    # do_transaction() returns true if succeeds; sets $db->error on failure:
#$self->set_rose_debug(1);
    my $ok = $db->do_transaction($new_practice);
#$self->set_rose_debug(0);

    return $ok ? 0 : 'update_practices() error - ' . $db->error;
}

# ------------------------------------------------------------------------------
# formats data into format required by referral_sources & parent_organisation tables:
sub _format_data_for_practices {
    my $self = shift;
    my $data = shift;

    # format post-code to uppercase:
    my $zip = $data->{practice_zip};
    $data->{practice_zip} = LIMS::Local::Utils::format_postcode($zip);
    
    # format description for parent_organisations table:
    $data->{description} = join ', ', map uc $data->{$_}, qw(practice_name practice_zip);
    
    # format display_name for referral_sources table:
    $data->{display_name} = join ', ', map $data->{$_},
        qw(practice_name practice_address practice_zip);
    
    # get referral_type object for referral_type_id:
    my $referral_type
        = LIMS::DB::ReferralType->new(description => $data->{referral_type})->load;
    $data->{referral_type_id} = $referral_type->id;
}

1;
