#!/usr/bin/perl

# just testing for dfv errors using LIMS::Validation profiles:

use Test::WWW::Mechanize::CGIApp;
use Data::Dumper;

use strict;
use warnings;

use Test::More tests => 76; #  use Test::More 'no_plan';

=begin: tests:
0) create some new records for this test suite (not tested)
1) new_patient validation profile
2) edit_patient validation profile (nhs_number)
3) edit_patient validation profile (dob)
4) edit_patient validation profile (> 1 record requires confirmation)
6) new_location profile

=cut

BEGIN {
    require 't/test-lib.pl';
}

my $mech = get_mech();

do_login();

my $dbh;

eval {
    $dbh = get_dbh() or die 'no database handle recieved from get_dbh';
};

warn $@ if $@;

# need to drop & re-create following tables:
foreach ( qw/ / ) { # none - using test-data.pl
    drop_and_recreate($_);
}

# create some new patient/request/patient_case records for this test suite:
{
    my $dbix = get_dbix();
    
    my $year = DateTime->now->year();
    my $now  = DateTime->now();
    
    # new data:
    my %new = (
        patients => [ # last_name, first_name, middle_name, dob, gender, nhs_no, created_at
            [ qw( green alan 1940-02-21 M), undef, $now ]
        ],
        patient_case => [ # patient_id, referral_source_id, unit_number
            [ 3, 1, 'ABC123' ],
        ],
        requests => [ # yr, request_id, patient_case_id, referrer_dept_id, now 
            [ $year, 3, 1, 2, $now ], # hospital referral - duplicate of request #1 
            [ $year, 4, 3, 2, $now ], 
        ],
        request_specimen => [ # request_id, specimen_id
            [ 3, 1 ],
            [ 4, 1 ],
        ],
    );

    my $test_data = get_test_data();

    while ( my ($tbl, $data) = each %new ) { # warn $tbl, "\n";
        my $fields = $test_data->{$tbl}->{fields}; # warn Dumper $fields;

        foreach my $data_set (@$data) { # warn $data_set, "\n";
            my $i = 0;
            # map field_name to its value:
            my %data = map { $fields->[$i++] => $_ } @$data_set; # warn Dumper \%data;

            $dbix->insert($tbl, \%data);
        }
    }
}

# new_patient validation profile:
$mech->get_ok('/patient');           # print_and_exit();

{
    my %patient = (
        last_name  => 'WHITE', # uppercase - tests field_filters
        first_name => 'Gary',
        nhs_number => 2222222222, # duplicate
        day        => 30,
        month      => 1,
        year       => 1950,
        gender     => 'M',
        referral_source_id => 1,
        unit_number => 'A123',
    );
    
    # test missing fields using local _test_missing_fields():
    _test_missing_fields(\%patient);
 
    # test missing unit_number & nhs_number:
    {
        my %tmp = %patient; # clone %patient
        map { $tmp{$_} = undef } qw(unit_number nhs_number);
        
        $mech->submit_form(fields => \%tmp);                 # print_and_exit();
        
        has_dfv_errors();
        has_formvalidator_error( get_messages('require_one') );
    }

    # require unique nhs_number:
    $mech->submit_form(fields => \%patient);                  # print_and_exit();    
    
    has_dfv_errors();
    has_duplicate();
    
    # reload page - no need to test:
    $mech->get('/patient');  
    
    # add 1111111111 to nhs_number to make unique:
    $patient{nhs_number} += 1111111111;
    
    # increment month to make invalid (30/Feb):
    $patient{month}++;
    
    $mech->submit_form(fields => \%patient);                  # print_and_exit();
    
    has_dfv_errors();
    $mech->content_contains(
        dfv_format('invalid_date'),
        'OK: invalid date detected',
    );

    # increment month again to make valid (30/March):
    $patient{month}++;
    
    # make year 2-digits:
    $patient{year} -= 1900;
    $mech->submit_form( fields => \%patient );           
    $mech->content_contains(
        dfv_format('year_digits'),
        'OK: year data length incorrect',
    );

    # year -> future:
    $patient{year} = DateTime->now->year() + 1;
    
    $mech->submit_form( fields => \%patient );            # print_and_exit();
    $mech->content_contains(
        dfv_format('future_date'),
        'OK: date in future detected OK',
    );

    # correct year to valid:
    $patient{year} = DateTime->now->year() - 1;
    $mech->submit_form(fields => \%patient);                  # print_and_exit();
    
    lacks_dfv_errors();                                      # print_and_exit();
}

# edit_patient validation profile (nhs_number):
my $last_patient_id = get_last_insert_id('patients');
$mech->get_ok('/patient/edit_patient/'.$last_patient_id);    # print_and_exit();
{
    # get patient details from db:
    my $dbix = get_dbix();
    my $sql = q!select last_name, first_name, year(dob) as 'year', month(dob) as
        'month', day(dob) as 'day', gender, nhs_number from patients where id = ?!;
    my $patient = $dbix->query($sql, $last_patient_id)->hash; # warn Dumper $patient;
    
    # test field_filters worked (_name's should be lowercase):    
    { # fail if tesed againt uppercase values:
        isnt($patient->{last_name},  'WHITE', 'OK: last_name not uppercase');
        is($patient->{last_name},    'white', 'OK: field_filter on last_name working');
        isnt($patient->{first_name}, 'Gary', 'OK: first_name not ucfirst');
        is($patient->{first_name},   'gary', 'OK: field_filter on first_name working');
    }
    
    # test missing fields using local _test_missing_fields():
    _test_missing_fields($patient);             # print_and_exit();

    # invalid nhs_number:
    $patient->{nhs_number} = 1234; # warn Dumper $patient;
    $mech->submit_form(fields => $patient);                 # print_and_exit();
    
    has_dfv_errors();
    has_invalid();

    # valid & duplicate nhs_number:
    $patient->{nhs_number} = 2222222222;
    $mech->submit_form(fields => $patient);               # print_and_exit();
    
    has_dfv_errors();
    has_duplicate();                                   # print_and_exit();    
    
    # valid & unique nhs_number:
    $patient->{nhs_number} = 5555555555;
    $mech->submit_form(fields => $patient);                # print_and_exit();
    
    lacks_duplicate();
    lacks_invalid();
    has_missing(); # still needs reason for edit

    $mech->field(error_code_id => 1);
    $mech->submit_form(fields => $patient);               # print_and_exit();

    lacks_invalid();
    lacks_duplicate();
    lacks_missing(); 
}

# edit_patient validation profile (dob):
$mech->get_ok('/patient/edit_patient/2');                    # print_and_exit();
{
    # change should affect only 1 record:
    $mech->has_tag(
        span => 'INFO: change affects this record only',
        'OK: single record change notice',
    );                                                        # print_and_exit(); 
    
    # dob = 04/10/1960 - make it invalid:
    $mech->field(day => 44);
    $mech->submit_form();                                     # print_and_exit();

    has_dfv_errors();
    $mech->content_contains(
        dfv_format('invalid_date'),
        'OK: invalid date detected',
    );
    
    # revert to valid dob:
    $mech->field(day => 14);
    $mech->submit_form();                                     # print_and_exit();
    
    lacks_duplicate();
    lacks_invalid();
    has_missing(); # still needs reason for edit

    $mech->field(error_code_id => 1);
    $mech->submit_form();                                     # print_and_exit();

    lacks_invalid();
    lacks_duplicate();
    lacks_missing(); 
}

# edit_patient validation profile (> 1 record - requires confirmation):
$mech->get_ok('/patient/edit_patient/1/1');                   # print_and_exit();
{
    # check similar patient data loaded:
    $mech->has_tag(
        p => 'Select a previous record or edit current record:',
        'OK: similar entries found'
    );
    
    foreach( qw/GREEN Alan 21.Feb.1940 [NULL]/ ) {
        $mech->has_tag(
            td => $_,
            'OK: expected field detected'
        );
    }
    $mech->has_tag_like(
        li => 'ABC123',
        'OK: expected field detected'
    );
    
    $mech->has_tag(
        span => 'WARNING: change affects 1 other record',
        'OK: correct number of records',
    );                                                        # print_and_exit();

    $mech->field(day => 11);
    $mech->field(error_code_id => 1);
    # confirmation missing:
    $mech->submit_form();                                    #  print_and_exit();
    
    has_dfv_errors();
    has_missing();                                           #  print_and_exit();

    $mech->field(confirmation => 1);
    $mech->submit_form();                                    #  print_and_exit();
    
    lacks_dfv_errors();
    lacks_missing();                                         #  print_and_exit();
}

SKIP: {
    skip('TODO: test consequence of editing nhs_number to null if unit_number also null', 1);
}

# new_location profile:
$mech->get_ok('/patient/select_patient/1');                  #  print_and_exit();
{
    # only required field is referral_source_id:
    $mech->submit_form(); # empty                              
    
    has_dfv_errors();
    has_missing();                                            # print_and_exit();

    my %data = (
        referral_source_id => 1,
        unit_number => 'ABC123',
    );
    
    $mech->submit_form(fields => \%data);                   # print_and_exit();
    
    lacks_dfv_errors();
}

sub _test_missing_fields {
    my $patient = shift;

    # test missing required on fields which should trigger 'missing':
    foreach my $field( qw/last_name first_name gender referral_source_id/ ) {
        # create temp hash with one field missing:
        my %tmp = %$patient; # clone %patient
        $tmp{$field} = undef; # warn Dumper \%tmp_user;

        $mech->submit_form(fields => \%tmp);
        
        # check we have dfv error:
        has_dfv_errors();
        has_missing();
    }

    # test missing dob:
    {
        my %tmp = %$patient; # clone %patient
        map { $tmp{$_} = undef } qw(day month year);
        
        $mech->submit_form(fields => \%tmp);                 # print_and_exit();
        
        has_dfv_errors();
        has_missing();
    }
}

