package AnonymisePatient;

# 'base' class for Anonymise::LIMS & Anonymise::HILIS3 - never called directly

use Moose;
use Data::Dumper;
use Config::Auto;
use FindBin qw($RealBin); # warn $RealBin;

# methods/accessors for anonymise_patient():
# TODO: combine existing_nhs_numbers & new_nhs_numbers functions - don't need both
has existing_nhs_numbers => ( is => 'ro', isa => 'ArrayRef', required => 1, auto_deref => 1 );
has all_names            => ( is => 'ro', isa => 'HashRef',  lazy_build => 1 );
has new_nhs_numbers      => ( is => 'rw', isa => 'HashRef',  default => sub { {} } );

has $_  => ( is  => 'ro', isa => 'ArrayRef', lazy_build => 1 )
    foreach qw( surnames male_names female_names first_names );

__PACKAGE__->meta->make_immutable;

sub get_substitutes {
	my $self = shift;

    my @last_names  = @{ $self->surnames };
    my @first_names = @{ $self->first_names };
    my @boys_names  = @{ $self->male_names };
    my @girls_names = @{ $self->female_names };

    my %substitutes = (
        last_names   => \@last_names,
        first_names  => \@first_names,
        male_names   => \@boys_names,
        female_names => \@girls_names,
    );

    return \%substitutes;
}

sub _build_all_names {
    my $self = shift;
	
	my $path_to_app = $self->path_to_app; # warn $path_to_app;
	
    my $names_src = "$path_to_app/setup/hilis3_convert/names.pl";
    my $names = Config::Auto::parse($names_src, format => 'perl');
    # print Dumper $names;

    return $names;
}

sub _build_surnames {
    my $self = shift;

    my $names = $self->all_names;
    return $names->{surnames};
}

sub _build_male_names {
    my $self = shift;

    my $names = $self->all_names;
    return $names->{male_names};
}

sub _build_female_names {
    my $self = shift;

    my $names = $self->all_names;
    return $names->{female_names};
}

sub _build_first_names {
    my $self = shift;

    my @boys_names  = @{ $self->male_names };
    my @girls_names = @{ $self->female_names };

    return [ @boys_names, @girls_names ];
}

# need to return unique valid 10-digit nhs_number:
sub make_nhsno {
    my $self = shift;

	my $new_nhs_number;

	TRY: while (1) { # $try++;
		my $potential_nhs_number
			= join '', map { int rand 9 } 1 .. 10; # warn $new_nhs_number;

		# try again if invalid:
		$self->_check_nhsno($potential_nhs_number) || next TRY;
		
        # try again if not unique:
		next TRY if
			$self->new_nhs_numbers->{$potential_nhs_number} ||
				grep $potential_nhs_number == $_, $self->existing_nhs_numbers;
			
		$new_nhs_number = $potential_nhs_number;
		
		# exit loop:
		last TRY;
	} # warn Dumper $new_nhs_numbers;
	
	$self->new_nhs_numbers->{$new_nhs_number}++; 
	
	return $new_nhs_number;
}

sub _check_nhsno {
    my $self  = shift;
	my $nhsno = shift; # _dump(Dumper $nhsno);

	$nhsno =~ s/\s+//g;

	return unless length $nhsno == 10; # require 10 consecutive numbers only

	my $product;

	# sum of (each of the first nine digits * weighting factor):
	for (0 .. 8) { # 1st 9 digits of NHS no
		$product += ( substr($nhsno, $_, 1) * (10 - $_) );
	}

	# Divide $product by 11 and establish the remainder. Subtract the remainder from 11 to give
	# the check digit. If the result is 11 then a check digit of 0 is used.
	my $remainder = $product % 11 ? 11 - ($product % 11) : '0';

	# If the result is 10 then the NHS NUMBER is invalid. Check the remainder matches the check
	# digit. If it does not, the NHS NUMBER is invalid.
	return $remainder == substr($nhsno, 9, 1) && $remainder != '10'; # true if NHSNo correct
}

1;
