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

// Java classes
import gov.va.med.esr.common.infra.ImpreciseDateUtils;
import gov.va.med.esr.common.model.ee.Eligibility;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.ee.IneligibilityFactor;
import gov.va.med.esr.common.model.ee.MonetaryBenefit;
import gov.va.med.esr.common.model.ee.MonetaryBenefitAward;
import gov.va.med.esr.common.model.ee.RatedDisability;
import gov.va.med.esr.common.model.ee.VerificationInfo;
import gov.va.med.esr.common.model.lookup.Disability;
import gov.va.med.esr.common.model.lookup.EligibilityType;
import gov.va.med.esr.common.model.lookup.EnrollmentPriorityGroup;
import gov.va.med.esr.common.model.lookup.EnrollmentPrioritySubGroup;
import gov.va.med.esr.common.model.lookup.EnrollmentStatus;
import gov.va.med.esr.common.model.lookup.Gender;
import gov.va.med.esr.common.model.lookup.Indicator;
import gov.va.med.esr.common.model.lookup.MonetaryBenefitType;
import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.rule.data.EEInputData;
import gov.va.med.esr.common.rule.data.PersonInputData;
import gov.va.med.esr.common.util.RuleAbstractTestCase;
import gov.va.med.fw.rule.RuleParameters;
import gov.va.med.fw.service.ServiceException;

import gov.va.med.ps.model.PersonVPID;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.Validate;


public class ProcessHealthBenefitProfileTest extends RuleAbstractTestCase
{
    private Person onFile = null;
    
    public ProcessHealthBenefitProfileTest(String testName) throws Exception 
    {
        super(testName);
    }
    
    /**
     * @see gov.va.med.fw.util.AbstractTestCase#customSetUp()
     */
    protected void customSetUp() throws Exception {
        super.customSetUp();
        onFile = this.buildSimplePerson();
      
    }
    
    /*  PresumptiveHBPEligibility Rule
     * when
{
    ?serviceConnectionInput: gov.va.med.esr.common.rule.ServiceConnectionInput();
    ?monetaryAwardInput: gov.va.med.esr.common.rule.MonetaryAwardInput();
    ?enrollmentInput: gov.va.med.esr.common.rule.EnrollmentInput();
    ?ineligibleInput: gov.va.med.esr.common.rule.IneligibleInput();
    ?ruleState: gov.va.med.fw.rule.RuleState();
    evaluate((?serviceConnectionInput.isEqual( ?serviceConnectionInput.getServiceConnectedPercentage(), ?serviceConnectionInput.toInteger( 0 ) )) &&
             (! (?monetaryAwardInput.isGreaterThan( ?monetaryAwardInput.toInteger( ?monetaryAwardInput.getTotalCheckAmount() ), 0 ))) &&
             (?serviceConnectionInput.doesRatedDisabilitiesHaveReceivedCode( Disability.CODE_UNSPECIFIED_NEUROSIS.getCode())) &&
             (((((?enrollmentInput.isEqual( ?enrollmentInput.getEnrollmentStatus(), EnrollmentStatus.CODE_REJECTED_BELOW_ENROLLMENT_GROUP_THRESHOLD.getCode() )) &&
                     (?enrollmentInput.isEqual(?enrollmentInput.getEnrollmentPriority(), EnrollmentPriorityGroup.GROUP_8.getCode())) &&
                     (?enrollmentInput.isEqual(?enrollmentInput.getEnrollmentSubPriority(), EnrollmentPrioritySubGroup.SUBGROUP_E.getCode()))) ||
                 ((?enrollmentInput.isEqual( ?enrollmentInput.getEnrollmentStatus(), EnrollmentStatus.CODE_NOT_ELIGIBLE_INELIGIBLE_DATE.getCode() )) &&
                     (?ineligibleInput.isAfter( ?ineligibleInput.getIneligibilityDate(),  ?ineligibleInput.toDate( "06/13/2013" )   )) &&
                     (?enrollmentInput.doesCalculatedSecondaryEligibilityCodeContain( EligibilityType.HUMANTARIAN_EMERGENCY.getCode() )))))));
}
then
{
    ?enrollmentInput.addHBPToList(HealthBenefitPlanType.CODE_PRESUMPTIVE.getCode());
    ?ruleState.setRuleExecuted(true);
}

 */
    
    /*(SC % = 0%) AND (exists DXCODE 9410) 
    AND
    (EnrollmentStatus = 'Rejected; Below Enrollment Group Threshold') AND (PG = 8e)
    */

    public void testPresumptiveHBPEligibilty_1() throws Exception{
        this.attachVerifiedEnrollment(onFile);
        this.getPersonService().save(onFile);
        Person incoming = (Person)onFile.clone();
        this.setServiceConnectedPercentage(new Integer(0), incoming);
        this.attachServiceConnectionAward(incoming, new Integer(0));
        
        RatedDisability rd1 = this.createRatedDisability(
                this.getLookupService()
                        .getDisabilityByCode(
                                Disability.CODE_UNSPECIFIED_NEUROSIS
                                        .getCode()), new Integer(0));
        incoming.getServiceConnectionAward().addRatedDisability(rd1);
       
        
        incoming.setEnrollmentDetermination(createEnrollmentDetermination(
                EnrollmentStatus.CODE_REJECTED_BELOW_ENROLLMENT_GROUP_THRESHOLD,
                EnrollmentPriorityGroup.GROUP_8,
                EnrollmentPrioritySubGroup.SUBGROUP_E, new BigDecimal(1)));
       
                        
        executeProcessHealthBenefitProfile(incoming, onFile);
        
       // this.setComplete();
       // System.out.println("Person id="
       //         + incoming.getPersonEntityKey().getKeyValueAsString());

        
       
    }
/*
 * (SC % = 0%) 
 * AND (exists DXCODE 9410)
 * AND (EnrollmentStatus = Not Eligible, Ineligible Date') 
 * AND (Ineligible Date is not NULL  >= 6/13/2013) 
 * AND (SecondaryEligibility = 'Humanitarian Emergency')
 */
    public void testPresumptiveHBPEligibilty_2() throws Exception{
        
        this.attachVerifiedEnrollment(onFile);
        Person pristine = this.getPersonService().save(onFile);
        Person incoming = (Person)onFile.clone();
        
        this.setServiceConnectedPercentage(new Integer(0), incoming);
        this.attachServiceConnectionAward(incoming, new Integer(0));
        
        RatedDisability rd1 = this.createRatedDisability(
                this.getLookupService()
                        .getDisabilityByCode(
                                Disability.CODE_UNSPECIFIED_NEUROSIS
                                        .getCode()), new Integer(0));
        incoming.getServiceConnectionAward().addRatedDisability(rd1);
        
        EnrollmentDetermination ed = createEnrollmentDetermination();
        ed.getEgtSetting().setCurrent(Boolean.TRUE);
        incoming.setEnrollmentDetermination(ed);
        
        incoming.getEnrollmentDetermination().setEnrollmentStatus(this.getLookupService().getEnrollmentStatusByCode(EnrollmentStatus.CODE_NOT_ELIGIBLE_INELIGIBLE_DATE.getCode()));
            
        IneligibilityFactor ineligFactor = new IneligibilityFactor();
        ineligFactor.setIneligibleDate(toDate( "07/13/2000" ));
        ineligFactor.setReason("some reason");
        incoming.setIneligibilityFactor(ineligFactor);
       
        Eligibility e = new Eligibility();
        e.setOther();     
        e.setType(getLookupService().getEligibilityTypeByCode(EligibilityType.HUMANTARIAN_EMERGENCY.getCode()));
        incoming.getEnrollmentDetermination().addSecondaryEligibility(e);
        
                              
        executeProcessHealthBenefitProfile(incoming, pristine);
        
       // this.setComplete();
       // System.out.println("Person id="
       //         + incoming.getPersonEntityKey().getKeyValueAsString());

        
       
    }
    
    
 
    protected EnrollmentDetermination createEnrollmentDetermination(
            EnrollmentStatus.Code enrollmentStatus,
            EnrollmentPriorityGroup.Code enrollmentPriorityGroup,
            EnrollmentPrioritySubGroup.Code enrollmentPrioritySubGroup,
            BigDecimal identifier) throws Exception {
        EligibilityType eligibilityType = (EligibilityType) this
                .getLookupService().getByCode(
                        EligibilityType.class,
                        EligibilityType.SC_LESS_THAN_50_PERCENT
                                .getCode());

        Eligibility eligibility = new Eligibility();
        eligibility.setPrimary();
        eligibility.setType(eligibilityType);

        EnrollmentDetermination enrollmentDetermination = this
                .createEnrollmentDetermination();
        enrollmentDetermination.setPrimaryEligiblity(eligibility);
        enrollmentDetermination.setEnrollmentStatus((EnrollmentStatus) this
                .getLookupService().getByCode(EnrollmentStatus.class,
                        enrollmentStatus));
        enrollmentDetermination.setPriorityGroup((EnrollmentPriorityGroup) this
                .getLookupService().getByCode(EnrollmentPriorityGroup.class,
                        enrollmentPriorityGroup));
        enrollmentDetermination
                .setPrioritySubGroup((EnrollmentPrioritySubGroup) this
                        .getLookupService().getByCode(
                                EnrollmentPrioritySubGroup.class,
                                enrollmentPrioritySubGroup));
        enrollmentDetermination.setIdentifier(identifier);
        return enrollmentDetermination;
    }
    

    private void executeProcessHealthBenefitProfile(Person incoming, Person pristine) throws Exception {
        
        onFile.setEnrollmentDetermination(incoming.getEnrollmentDetermination());
        PersonInputData data = new PersonInputData(incoming, onFile, pristine, false);
              
        RuleParameters ruleParameters = this
                .getProcessHealthBenefitProfileRuleParameters();
        this.getRuleFlowService().execute(ruleParameters, data);
    }

    /**
     * @return Returns the processHealthBenefitProfileRuleParameters.
     */
    private RuleParameters getProcessHealthBenefitProfileRuleParameters()
            throws ServiceException {
        return (RuleParameters) applicationContext.getBean("processHealthBenefitProfileRuleParameters");
    }
//  The Simple Person needs to remain "simple." Please don't add an E&E
    // factors such
    // as POW or PH.
    protected Person doBuildSimplePerson(boolean includeIdentityTraits,
            String vpidValue, String claimFolderNumber) throws Exception {
        Person person = new Person();

        // these are marked as private since application should never set
        if (vpidValue == null)
            vpidValue = PersonVPID.DEFAULT_TESTING_VPID;
        PersonVPID vpid = new PersonVPID(vpidValue);
        vpid.attach(person);

        person.setSensitiveRecord(Boolean.FALSE);
        // Needs to be true otherwise most e&e rules would fail
        person.setVeteran(Boolean.TRUE);
        
        
        if (claimFolderNumber == null)
            person.setClaimFolderNumber(RandomStringUtils.randomNumeric(9));
        else
            person.setClaimFolderNumber(claimFolderNumber);

        if (includeIdentityTraits) {
            person.addName(createName("TEST", "PERSON",
                    NameType.LEGAL_NAME.getName()));
            person.setBirthRecord(this.createBirthRecord(ImpreciseDateUtils
                    .createImpreciseDate(1950, 1, 1)));
            person.setGender(this.getLookupService().getGenderByCode(Gender.MALE
                    .getName()));
        }
        return person;
    }

    // Build a "bare-bones" person
    protected Person buildSimplePerson() throws Exception {
        return doBuildSimplePerson(true, null, null);
    }
    /**
     * @see gov.va.med.fw.util.AbstractTestCase#customTearDown()
     */
    protected void customTearDown() throws Exception {
        super.customTearDown();
        onFile = null;
    }

    /**
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        Validate.notNull(this.getRuleValidationService(), "A rule validation service is required");
    }
    
    private Date toDate(String value) throws ParseException {
        Validate.notNull(value, "A date string must not be NULL");
        Date parsed = toDate(value, SimpleDateFormat.SHORT);
        if (logger.isDebugEnabled()) {
            logger.debug(" Input date string: " + value);
            logger.debug(" Parsed date: " + parsed);
        }
        return parsed;
    }
    
    private Date toDate(String value, int pattern) throws ParseException {
        Validate.notNull(value, "A date string must not be NULL");
        Date parsed = SimpleDateFormat.getDateInstance(pattern).parse(value);
        if (logger.isDebugEnabled()) {
            logger.debug(" Input date string: " + value);
            logger.debug(" Parsed date: " + parsed);
        }
        return parsed;
    }
    
}
