/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.service;

// Java classes
import gov.va.med.esr.common.batchprocess.SSASSNVerificationData;
import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.lookup.EmailType;
import gov.va.med.esr.common.model.lookup.Gender;
import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.lookup.PhoneType;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.party.Email;
import gov.va.med.esr.common.model.party.Phone;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.util.RuleAbstractTestCase;
import gov.va.med.esr.service.external.demographics.DemographicsChangeEvent;
import gov.va.med.esr.service.external.demographics.DemographicsChangeSummary;
import gov.va.med.esr.service.external.demographics.DemographicsChangeType;
import gov.va.med.esr.service.external.person.VPIDEntityKey;

import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.RandomStringUtils;


public class DemographicServiceTest extends RuleAbstractTestCase {

    Person person = null;
    
    private DemographicService demographicService = null;
    
    public DemographicServiceTest(String testName) {
        super(testName);
    }

    protected void customSetUp() throws Exception { 
        super.customSetUp();
        person  = this.buildPerson();
    }
	public void testDateOfDeathFromIdm() throws Exception {
		Person onFile = this.buildSimplePerson();
		this.attachVerifiedEnrollment(onFile);
		this.attachMeansTestWithMtCopayExempt(onFile);
	    SSN ssn = this.createSSN(); 
	    ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
        onFile.addSsn(ssn);		
		Person incoming = this.savePerson(onFile);	
		VAFacility sendingFacility = this.getLookupService().getVaFacilityByStationNumber(VAFacility.CODE_HEC.getName());				

		Date dateOfDeath = new Date();
		Person updated = this.getDemographicService().processDateOfDeathFromIdm(incoming, dateOfDeath);
		assertNotNull(updated.getDeathRecord());
		System.out.println("Person id="
				+ updated.getPersonEntityKey().getKeyValueAsString());
		//this.setComplete(); // only enable this when you want to test persistence capability
	}		
	 	
    public void testProcessExternalDemographicChanges() throws Exception {
        Person incoming = this.getPersonService().getPerson(CommonEntityKeyFactory.createVPIDEntityKey("0000001000000001V401987000020"));        

        if (incoming == null) {
            fail("incoming person is null");
        }
        
        Set changes = new HashSet();
        DemographicsChangeEvent demographicsChangeEvent = new  DemographicsChangeEvent( DemographicsChangeType.DATE_OF_DEATH_CHANGE);
        
        changes.add(demographicsChangeEvent);
        //0000001000000001V401987000020
        //vpid id 63348
        MockKey mk = new MockKey();
        DemographicsChangeSummary demographicsChangeSummary = new DemographicsChangeSummary(mk, changes);
        
        this.getDemographicService().processExternalDemographicsChange(demographicsChangeSummary);
    }    

    public void testUpdateAddressForExistingPerson() throws Exception {
		Person person = getPersonService().getPerson(
				CommonEntityKeyFactory.createPersonIdEntityKey("72137"));
		person = (Person) person.clone(); // simulates incoming
		person.getPermanentAddress().setLine3(RandomStringUtils.randomAlphabetic(10));
		this.getDemographicService().updateContactInformation(person);
    }
    
   
    public void testUpdateIncomeTestLastEditedDate() throws Exception
    {
		Person person = getPersonService().getPerson(
				CommonEntityKeyFactory.createPersonIdEntityKey("4"));
		Map incometestsMap = person.getIncomeTests();

		Set incometests = incometestsMap.entrySet();
		IncomeTest test = (IncomeTest) incometestsMap.get(new Integer(2005));
		this.getDemographicService().updateIncomeTestLastEditedDate(test, new Date());
			
			System.out.println("id = " + test.getIncomeTestStatus().getEntityKey());
			//System.out.println("lastEditedDate = " + lastEditedDate);
    	
    }
    
    public void testUpdateContactInformationAddressForPermanent() throws Exception {
        PhoneType homePhone = this.getLookupService().getPhoneTypeByCode(PhoneType.CODE_HOME.getName());
        EmailType privEmail = this.getLookupService().getEmailTypeByCode(EmailType.CODE_PRIVATE.getName());
        PhoneType busPhone = this.getLookupService().getPhoneTypeByCode(PhoneType.CODE_BUSINESS.getName());
        EmailType busEmail = this.getLookupService().getEmailTypeByCode(EmailType.CODE_BUSINESS.getName());
        
        person.addPhone(this.createPhone(homePhone));
        person.addEmail(this.createEmail(privEmail));
        Person incoming = this.getPersonService().save(person);        
        
        this.addPermanentAddress(incoming, Calendar.getInstance()
                .getTime(), null);

        assertTrue(incoming.getPhones().size() == 1);
        assertTrue(incoming.getEmails().size() == 1);        
        
        incoming.addPhone(this.createPhone(busPhone));
        incoming.addPhone(this.createPhone(busPhone));        
        incoming.addEmail(this.createEmail(busEmail));
        assertTrue(incoming.getPhones().size() == 3);        
        assertTrue(incoming.getEmails().size() == 2);        
        
        Person result = this.getDemographicService().updateContactInformation(incoming);
        this.assessPermanentAddressUpdateResults(incoming, result);
        assertTrue(result.getPhones().size() == 3);        
        assertTrue(result.getEmails().size() == 2);
   }
    
    public void testAddPermanentAddressForNewPerson() throws Exception {

        Person onFile = buildSimplePerson();
        Person incoming = this.getPersonService().save(onFile);        
        this.addPermanentAddress(incoming, Calendar.getInstance()
                .getTime(), null);
        
        Person result = this.getDemographicService().updateContactInformation(incoming);
        assertEquals(incoming.getAddresses().size(), result.getAddresses().size());
   }    
    
    public void testPreferredFac1() throws Exception {
        Person onFile = buildSimplePerson();
        onFile.setMostRecentPreferredFacility(this.getLookupService().getVaFacilityByCode("722"));
        Person incoming = this.getPersonService().save(onFile);
        incoming.setMostRecentPreferredFacility(null);
        Person updated = this.getDemographicService().updateDemographicInformation(incoming);
        assertNull(updated.getMostRecentPreferredFacility());

    }
    
    public void testPreferredFac2() throws Exception {
        Person onFile = buildSimplePerson();
        Person incoming = this.getPersonService().save(onFile);
        incoming.setMostRecentPreferredFacility(this.getLookupService().getVaFacilityByCode("742"));
        Person updated = this.getDemographicService().updateDemographicInformation(incoming);
        assertNotNull(updated.getMostRecentPreferredFacility());
    }             
    
    public void testDefect3970FromUI() throws Exception {
        Person onFile = buildSimplePerson();
        onFile = doBuildSimplePerson(true, "0000001000210017V228032000000", null);
        Person updated = this.getPersonService().save(onFile);
        Person incoming = (Person)updated.clone();
        incoming.setUserEnrolleeValidThrough(new Integer(2006));
                
        Person result = this.getDemographicService().updateDemographicInformation(incoming);  
        assertEquals(result.getUserEnrolleeValidThrough().intValue(), (new Integer(2006)).intValue());
        logger.info("Completed Test");
    }          
    
    public void testDefect6974FromUI() throws Exception {
        PersonIdentityTraits traits = this.getPsDelegateService().getIdentityTraits(CommonEntityKeyFactory.createVPIDEntityKey("0000001000210017V228032000000"));
        Person onFile = doBuildSimplePerson(true, "0000001000210017V228032000000", null);
        Person updated = this.getPersonService().save(onFile);
        
        Person incoming = (Person)updated.clone();
        
        SSN officialSSN = incoming.getOfficialSsn();
        
        //convertBean
        if (officialSSN == null)
        {
            // Create a new ssn if it doesn't already exists
            officialSSN = new SSN();
            officialSSN.setType(
                (SSNType)this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getName()));
            incoming.addSsn(officialSSN);
        }

        
        // SSA Verification Status - invalid 
        String invalidCode = SSAVerificationStatus.INVALID_PER_SSA.getName();
        SSAVerificationStatus status = this.getLookupService().getSSAVerificationStatusByCode(invalidCode);
        officialSSN.setSsaVerificationStatus(status); 


/*        
        //DOB required
        incoming.setBirthRecord(this.createBirthRecord(ImpreciseDateUtils.createImpreciseDate(
                1907, 8, 8)));

        Person onFile =  this.getPersonService().getPerson(
                (PersonEntityKey)incoming.getEntityKey());
        
        incoming.getOfficialSsn();
        onFile.getOfficialSsn();
        
        this.getMergeRuleService().mergeIdentityTraits(incoming, onFile);
*/
        //update when business/rule services are ready
        Person result = getDemographicService().updateIdentityTraits(incoming);
         
        assertEquals(result.getOfficialSsn().getSsaVerificationStatus().getCode(), "2");
        logger.info("Completed Test");
    }        
    
/*    
    private void convertFormtoPerson(DemographicIdentityTraitsForm form, Person person)
    throws ConversionServiceException
{
    LookupCacheService lookupCacheService = getLookupCacheService();
    try
    {
        // Name Information
        Name name = person.getLegalName();
        if (name == null)
        {
            name = new Name();
            name.setType(
                (NameType)lookupCacheService.getByCodeFromCache(NameType.class, NameType.LEGAL_NAME.getName()));
            person.setLegalName(name);
        }

        name.setPrefix(StringUtils.isBlank(form.getPrefix()) ? null : form.getPrefix());
        name.setGivenName(StringUtils.isBlank(form.getFirstName()) ? null : form.getFirstName());
        name.setMiddleName(StringUtils.isBlank(form.getMiddleName()) ? null : form.getMiddleName());
        name.setFamilyName(StringUtils.isBlank(form.getLastName()) ? null : form.getLastName());
        name.setSuffix(StringUtils.isBlank(form.getSuffix()) ? null : form.getSuffix());
        person.setGender((Gender)lookupCacheService.getByCodeFromCache(Gender.class, form.getGender()));

        // SSN Information
        if (isAnySsnInformationOnForm(form))
        {
            SSN officialSSN = person.getOfficialSsn();
            if (officialSSN == null)
            {
                // Create a new ssn if it doesn't already exists
                officialSSN = new SSN();
                officialSSN.setType(
                    (SSNType)lookupCacheService.getByCodeFromCache(SSNType.class, SSNType.CODE_ACTIVE.getName()));
                person.addSsn(officialSSN);
            }

            // SSN
            officialSSN.setSsnText(StringUtils.isBlank(SSN.formatSSN(form.getSsn())) ? null :
                SSN.formatSSN(form.getSsn()));

            // Pseudo SSN Reason
            if (StringUtils.isNotEmpty(form.getPseudoSsnReason()))
            {
                officialSSN.setPseudoSSNReason((PseudoSSNReason)lookupCacheService.getByCodeFromCache(
                    PseudoSSNReason.class, form.getPseudoSsnReason()));
            }
            else
            {
                officialSSN.setPseudoSSNReason(null);
            }

            // Source Of Change
            if (StringUtils.isNotEmpty(form.getSsnSourceOfChange()))
            {
                officialSSN.setSourceOfChange((SSNChangeSource)lookupCacheService.getByCodeFromCache(
                    SSNChangeSource.class, form.getSsnSourceOfChange()));
            }
            else
            {
                officialSSN.setSourceOfChange(null);
            }

            // SSA Verification Status
            if (StringUtils.isNotEmpty(form.getSsaVerificationStatus()))
            {
                officialSSN.setSsaVerificationStatus((SSAVerificationStatus)lookupCacheService
                    .getByCodeFromCache(SSAVerificationStatus.class, form.getSsaVerificationStatus()));
            }
            else
            {
                officialSSN.setSsaVerificationStatus(null);
            }
        }
        else
        {
            SSN officialSSN = person.getOfficialSsn();
            if (officialSSN != null)
            {
                person.removeSsn(officialSSN);
            }
        }

        // DOB
        BirthRecord birthRecord = person.getBirthRecord();
        if (StringUtils.isNotEmpty(form.getDateOfBirth()))
        {
            if (birthRecord == null)
            {
                // Create a new record
                birthRecord = new BirthRecord();
                person.setBirthRecord(birthRecord);
            }
            birthRecord.setBirthDate(DateUtils.getImpreciseDate(form.getDateOfBirth()));
        }
        else
        {
            if (birthRecord != null)
            {
                // TODO Check whether we need to delete the date of birth if user deletes it ?
                birthRecord.setBirthDate(null);
            }
        }
    }
    catch (Exception ex)
    {
        throw new ConversionServiceException("Conversion Failed", ex);
    }
}
*/
    public void testDefect4109FromUI() throws Exception {
        Person onFile = buildSimplePerson();
        Person updated = this.getPersonService().save(onFile);
        Person incoming = (Person)updated.clone();
        SSN ssn = this.createSSN();
        ssn.setPseudoSSNReason(this.getLookupService().getPseudoSSNReasonByCode("2"));
        ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getCode()));
        incoming.addSsn(ssn);
        incoming.setUserEnrolleeValidThrough(new Integer(2006));
        assertNotNull(incoming.getOfficialSsn());
        assertNotNull(incoming.getOfficialSsn().getPseudoSSNReason());
        Person result = this.getDemographicService().updateIdentityTraits(incoming);  

        assertNotNull(result.getOfficialSsn());
        assertNotNull(result.getOfficialSsn().getPseudoSSNReason());
        logger.info("Completed Test");
    }              
    
    public void testSSN4IdM1302FromUI() throws Exception {
        PersonIdentityTraits traits = this.getPsDelegateService().getIdentityTraits(CommonEntityKeyFactory.createVPIDEntityKey("0000001008591040V583029000000"));
    	
    	Person person = this.getPersonService().find(traits);
    	
    	SSN ssn = person.getOfficialSsn();
    	ssn.setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode("0"));
    	ssn.setSsaVerificationDate(new Date());
    	ssn.setSourceOfChange(this.getLookupService().getSSNChangeSourceByCode("01"));
    	ssn.setSsaMessage(this.getLookupService().getSSAMessageByCode("2"));
    	
    	this.getPersonService().updateProfileForESRCorrelation(person);
    	//test result
//        <urn:asOtherIDs classCode="SSN">
//        <urn:id extension="222001111" root="2.16.840.1.113883.4.1"/>
//        <urn:statusCode code="0"/>
//        <urn:effectiveTime value="20111205"/>
//        <urn:scopingOrganization classCode="ORG" determinerCode="INSTANCE">
//          <urn:id root="2.16.840.1.113883.4.1"/>
//          <urn:code code="01" displayName="VAMC">
//            <urn:originalText>Name and Date Of Birth match, Sex does not</urn:originalText>
//          </urn:code>
//        </urn:scopingOrganization>
//      </urn:asOtherIDs>
    } 
    
    
    public void testPreferredFac3() throws Exception {
        Person onFile = buildSimplePerson();
        onFile.setMostRecentPreferredFacility(this.getLookupService().getVaFacilityByCode("722"));        
        Person incoming = this.getPersonService().save(onFile);
        incoming.setMostRecentPreferredFacility(this.getLookupService().getVaFacilityByCode("742"));
        Person updated = this.getDemographicService().updateDemographicInformation(incoming);
        assertTrue(updated.getMostRecentPreferredFacility().getCode().equals(incoming.getMostRecentPreferredFacility().getCode()));
        this.setComplete();        
    }                 
    
    public void testDeletePhoneEmail() throws Exception {
        Person person = this.buildPerson();
        PhoneType homePhoneType = this.getLookupService().getPhoneTypeByCode(PhoneType.CODE_HOME.getName());
        EmailType privEmailType = this.getLookupService().getEmailTypeByCode(EmailType.CODE_PRIVATE.getName());
        Phone homePhone1 = this.createPhone(homePhoneType);
        Phone homePhone2 = this.createPhone(homePhoneType);
        Email privEmail1 = this.createEmail(privEmailType);
        Email privEmail2 = this.createEmail(privEmailType);        
        
        person.addPhone(homePhone1);
        person.addPhone(homePhone2);        
        person.addEmail(privEmail1);
        person.addEmail(privEmail2);
        assertTrue(person.getPhones().size() == 2);
        assertTrue(person.getEmails().size() == 2);        
        Person incoming = this.getPersonService().save(person);

        assertTrue(incoming.getEmails().size() == 2);
        assertTrue(incoming.getPhones().size() == 2);        
        
        this.addPermanentAddress(incoming, Calendar.getInstance()
                .getTime(), null);
        incoming.removeEmail(privEmail2);
        incoming.removePhone(homePhone2);
        
        Person result = this.getDemographicService().updateContactInformation(incoming);
        this.assessPermanentAddressUpdateResults(incoming, result);
        assertTrue(result.getEmails().size() == 1);
        assertTrue(result.getPhones().size() == 1);
    }    

    public void testUpdateDemographicDOD() throws Exception {
        attachDeathRecord(person);
        this.getPersonService().save(person);
        person.getDeathRecord().setDeathDate(ImpreciseDateUtils.createImpreciseDate(2004, 1, 1));
        Person result = this.getDemographicService().updateDemographicInformation(person);
        assertTrue(person.getDeathRecord().getDeathDate().equals(result.getDeathRecord().getDeathDate()));        
    }
    
    public void testUpdateDemographicClaimData() throws Exception {
        Person onFile = this.buildSimplePerson();
        this.attachVerifiedEnrollment(onFile);
        Person incoming = this.savePerson(onFile);
        incoming.setClaimFolderLocation(this.getRandomVAFacility());
        incoming.setClaimFolderNumber("12345");

        Person result = this.getDemographicService().updateDemographicInformation(incoming);
        assertTrue(result.getClaimFolderNumber().equals(incoming.getClaimFolderNumber()));        
        assertTrue(result.getClaimFolderLocation().equals(incoming.getClaimFolderLocation()));
    }    
    
    public void testDeleteDemographicDOD() throws Exception {
        attachDeathRecord(person);
        // Save with DOD
        this.getPersonService().save(person);
        
        //delete DOD
        person.setDeathRecord(null);
        
        Person result = this.getDemographicService().updateDemographicInformation(person);
        
        // should be null
        assertNull(result.getDeathRecord());        
    }    
    
    public void testUpdateIdentityTraits() throws Exception {
        Person onFile = buildSimplePerson();
        this.attachVerifiedEnrollment(onFile);
        onFile.setGender(this.getLookupService().getGenderByCode(Gender.MALE.getCode()));        
        Name name = new Name();
        name.setPrefix("Mr");
        name.setFamilyName("FamilyName");
        name.setGivenName("GivenName");
        name.setType(this.getLookupService().getNameTypeByCode(NameType.LEGAL_NAME.getCode()));
        onFile.setLegalName(name);
//        DeathRecord dr = new DeathRecord();
//        dr.setDeathDate(ImpreciseDateUtils.createImpreciseDate(1949,1,1));
//        onFile.setDeathRecord(dr);
        BirthRecord br = new BirthRecord();        
        br.setBirthDate(ImpreciseDateUtils.createImpreciseDate(1952,1,1));
        onFile.setBirthRecord(br);
        Person incoming = this.savePerson(onFile);
        incoming.getLegalName().setGivenName("Modified");
        incoming.setGender(this.getLookupService().getGenderByCode(Gender.AMBIGUOUS.getCode()));
        ImpreciseDate id = ImpreciseDateUtils.createImpreciseDate(1952,1,2);
        incoming.getBirthRecord().setBirthDate(id);
        Person updated = this.getDemographicService().updateIdentityTraits(incoming);
        assertTrue(updated.getGender().getCode().equals(Gender.AMBIGUOUS.getCode()));
        assertTrue(updated.getBirthRecord().getBirthDate().equals(id));        
        assertTrue(updated.getLegalName().getGivenName().equals("Modified"));        
    }                     
    
    public void testProcessSSNVerificationResponse() throws Exception {
        Person person = this.getPerson("376764805");      
 //       Person person = this.getPerson("2181");      
//        person.addSsn(this.createSSN());
 //       SSN ssn = (SSN)person.getSsns().iterator().next();
   //     ssn.setType(this.getLookupService().getSSNTypeByCode(SSNType.CODE_ACTIVE.getCode()));
        Name name = (Name)person.getNames().iterator().next();
//        Person incoming = this.getPersonService().save(person);
        SSASSNVerificationData data = new SSASSNVerificationData();
        data.setHECInternalID("100261500");
        data.setFirstName(name.getGivenName());
        data.setMiddleInitial(name.getMiddleName());
        data.setLastName(name.getFamilyName());
        data.setGender(person.getGender().getCode());
        data.setDateOfBirth(person.getBirthRecord().getBirthDate());
        data.setSsn(person.getOfficialSsn().getSsnText());
        //data.setSsaVerificationStatus(this.getLookupService().getSSAVerificationStatusByCode(SSAVerificationStatus.INVALID_PER_SSA.getCode()));
        data.setVerificationCode(SSAVerificationStatus.INVALID_PER_SSA.getCode());
        

        this.getDemographicService().updateSSNVerificationResponse(data);
        this.setComplete();
    }    
    
    /**
     * @return Returns the demographicService.
     */
    public DemographicService getDemographicService() {
        return demographicService;
    }

    /**
     * @param demographicService The demographicService to set.
     */
    public void setDemographicService(DemographicService demographicService) {
        this.demographicService = demographicService;
    }    
    
    public class MockKey implements VPIDEntityKey {
        public String getVPID() {
            return "0000001000000001V401987000020";
        }
        public void setDeprecated(boolean deprecated) {
            
        }
        public boolean isDeprecated() {
            return false;
        }
    }
}
