package gov.va.med.esr.service;

import gov.va.med.esr.common.util.RuleAbstractTestCase;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ObjectUtils;

import gov.va.med.esr.common.persistent.history.HistoryDAO;
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.person.Person;
import gov.va.med.esr.common.model.person.DeathRecord;
import gov.va.med.esr.common.model.person.SSN;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.common.model.ee.EGTSetting;
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.RatedDisability;
import gov.va.med.esr.common.model.ee.VerificationInfo;
import gov.va.med.esr.common.model.financials.Income;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.lookup.AssetType;
import gov.va.med.esr.common.model.lookup.DeathDataSource;
import gov.va.med.esr.common.model.lookup.EligibilityType;
import gov.va.med.esr.common.model.lookup.EligibilityFactor;
import gov.va.med.esr.common.model.lookup.EligibilityVerificationSource;
import gov.va.med.esr.common.model.lookup.EnrollmentSource;
import gov.va.med.esr.common.model.lookup.IncomeTestType;
import gov.va.med.esr.common.model.lookup.MeansTestStatus;
import gov.va.med.esr.common.model.lookup.MessageType;
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.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.service.impl.HistoricalInfo;
import gov.va.med.esr.service.impl.ChangeEvent;
import gov.va.med.fw.model.AbstractEntity;


/**
 * Test class to assess enrollment history changes
 * 
 * @author DNS   ruizc
 *
 */
public class EnrollmentDeterminationHistory extends RuleAbstractTestCase {
	
	public EnrollmentDeterminationHistory(String testName) {
		super(testName);
	}

	protected void customSetUp() throws Exception {
		super.customSetUp();
	}
	
	public void testEnrollmentDeterminationMatch() throws Exception {
		Person onFile = buildSimplePerson(); // bare-bones person
		onFile.setEnrollmentDetermination(this.createEnrollmentDetermination(EnrollmentSource.CODE_HEC.getCode(), 
				getDate(2001,1,1), getDate(2001,1,1), VAFacility.CODE_HEC.getCode(), 
				null,//EnrollmentPriorityGroup.GROUP_8.getCode(), 
				null,//EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode()));
		Eligibility e = new Eligibility();
		e.setType(this.getLookupService().getEligibilityTypeByCode(	EligibilityType.NSC.getCode()));		
		onFile.getEnrollmentDetermination().setPrimaryEligiblity(e);
		EnrollmentDetermination curr = onFile.getEnrollmentDetermination();
		System.out.println("curr priority=" + curr.getPriorityGroup() + 
				"  subg=" + curr.getPrioritySubGroup() +
				" status=" + curr.getEnrollmentStatus() + " prior groups=" +
				curr.getInitialPriorityGroup() + curr.getInitialPrioritySubGroup());		
		System.out.println("current egt=" + curr.getEgtSetting());		
		Person incoming = savePerson(onFile);
		this.getEnrollmentRuleService().calculateEE(incoming, true, false);
		EnrollmentDetermination ed = incoming.getEnrollmentDetermination();
		// ed.setEffectiveDate(getDate(2001,1,1));
		// ed.setEnrollmentDate(new Date());
		if (!AbstractEntity.matchesDomainValues(onFile, incoming)) {
			// Merge the results
			System.out.println("don't match");
			System.out.println("result priority=" + ed.getPriorityGroup() + 
					"  subg=" + ed.getPrioritySubGroup() +
					" status=" + ed.getEnrollmentStatus() + " prior groups=" +
					ed.getInitialPriorityGroup() + ed.getInitialPrioritySubGroup());
			System.out.println("result egt=" + ed.getEgtSetting());			
		}		
	}
	
	public void testSimpleMatch() throws Exception {
		PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("373971922"));
		Person onFile = this.getPersonService().getPerson(personKey);   		

		EnrollmentDetermination ed = (EnrollmentDetermination)onFile.getEnrollmentDetermination().clone();
		//ed.setPriorityGroup(null);
		System.out.println("priority=" + ed.getPriorityGroup());
		this.getEnrollmentRuleService().calculateEE(onFile, true, false);		
		boolean flag =  this.getMatchRuleService().match(ed, onFile.getEnrollmentDetermination());
		if (!AbstractEntity.matchesDomainConcept(ed, onFile.getEnrollmentDetermination())) {
			// Merge the results
			System.out.println("don't match");
			System.out.println("result priority=" + ed.getPriorityGroup() + 
					"  subg=" + ed.getPrioritySubGroup() +
					" status=" + ed.getEnrollmentStatus() + " prior groups=" +
					ed.getInitialPriorityGroup() + ed.getInitialPrioritySubGroup());
			System.out.println("result egt=" + ed.getEgtSetting());			
		}		
	}
	public void testSimpleEnrollmentMatch() throws Exception {
		Eligibility e1 = new Eligibility();
		e1.setType(this.getLookupService().getEligibilityTypeByCode(	
				EligibilityType.NSC.getCode()));	
		EnrollmentDetermination ed1 = this.createEnrollmentDetermination(
				EnrollmentSource.CODE_HEC.getCode(),getDate(2001,1,1), getDate(2001,1,1), VAFacility.CODE_HEC.getCode(), 
				EnrollmentPriorityGroup.GROUP_8.getCode(), 
				EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode());
		ed1.setPrimaryEligiblity(e1);
		Eligibility e2 = new Eligibility();
		e2.setType(this.getLookupService().getEligibilityTypeByCode(	
				EligibilityType.SC_LESS_THAN_50_PERCENT.getCode()));			
		EnrollmentDetermination ed2 = this.createEnrollmentDetermination(
				EnrollmentSource.CODE_HEC.getCode(),getDate(2002,1,1), getDate(2002,1,1), VAFacility.CODE_HEC.getCode(), 
				EnrollmentPriorityGroup.GROUP_8.getCode(), 
				EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode());		
		ed2.setPrimaryEligiblity(e2);
	
			
		if (!AbstractEntity.matchesDomainConcept(ed1, ed2)) {
			// Merge the results
			System.out.println("Domain Concept does not match");
		}
		else
			System.out.println("Domain Concept match");
		
		if (!AbstractEntity.matchesDomainValues(ed1, ed2)) {
			// Merge the results
			System.out.println("Domain Values don't match");
		}
		else 
			System.out.println("Domain Values match");
	}	
	public void testEnrollmentMerge() throws Exception {
		Eligibility e1 = new Eligibility();
		e1.setType(this.getLookupService().getEligibilityTypeByCode(	
				EligibilityType.NSC.getCode()));
		Eligibility e11 = new Eligibility();		
		e11.setFactor(this.getLookupService().getEligibilityFactorByCode(	
				EligibilityFactor.AGENT_ORANGE_EXPOSURE.getCode()));		
		EnrollmentDetermination ed1 = this.createEnrollmentDetermination(
				EnrollmentSource.CODE_HEC.getCode(),getDate(2001,1,1), getDate(2001,1,1), VAFacility.CODE_HEC.getCode(), 
				EnrollmentPriorityGroup.GROUP_8.getCode(), 
				EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode());
		ed1.setPrimaryEligiblity(e1);
		Eligibility e2 = new Eligibility();
		e2.setType(this.getLookupService().getEligibilityTypeByCode(	
				EligibilityType.NSC.getCode()));
		Eligibility e22 = new Eligibility();
		e22.setFactor(this.getLookupService().getEligibilityFactorByCode(	
				EligibilityFactor.AGENT_ORANGE_EXPOSURE.getCode()));					
		EnrollmentDetermination ed2 = this.createEnrollmentDetermination(
				EnrollmentSource.CODE_HEC.getCode(),getDate(2002,1,1), getDate(2002,1,1), VAFacility.CODE_HEC.getCode(), 
				EnrollmentPriorityGroup.GROUP_8.getCode(), 
				EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode());		
		ed2.setPrimaryEligiblity(e2);

		this.getMergeRuleService().mergeEnrollmentDetermination(ed1, ed2);
	}		
	private EnrollmentDetermination createEnrollmentDetermination(
			String source, Date effectiveDt, Date enrollmentDt,
			String facility, String priority, String subPriority, String status)
			throws Exception {
		EnrollmentDetermination edt = new EnrollmentDetermination();
		edt.setCalculationSource(this.getLookupService().getEnrollmentSourceByCode(source));
		edt.setEffectiveDate(effectiveDt);
		edt.setEnrollmentDate(enrollmentDt);
		edt.setFacilityReceived(this.getLookupService().getVaFacilityByCode(facility));
		edt.setPriorityGroup(priority != null ? 
				this.getLookupService().getEnrollmentPriorityGroupByCode(priority) : null);
		edt.setPrioritySubGroup(subPriority != null ? 
				this.getLookupService().getEnrollmentPrioritySubGroupByCode(subPriority) : null);
		edt.setEnrollmentStatus(status != null ? 
				this.getLookupService().getEnrollmentStatusByCode(status) : null);		
		EGTSetting egt = this.getEgtService().getCurrentEGTSetting();
		edt.setEgtSetting(egt);
		return edt;
	}
	
	
	public void testUpdateEligibilityData() throws Exception {
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();        
        this.attachServiceConnectionAward(incoming, new Integer(0));
		this.getEligibilityEnrollmentService().updateEligibilityData(incoming);
		this.setComplete();
	}
	public void testUpdateToSC10percent() throws Exception {
		// 375132559  375133921
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone(); 
        incoming.getServiceConnectionAward().setServiceConnectedPercentage(new Integer(10));
        incoming.getServiceConnectionAward().addRatedDisability(this.createRatedDisability());        
        incoming.getServiceConnectionAward().setServiceConnectedIndicator(Boolean.TRUE);
		this.getEligibilityEnrollmentService().updateEligibilityData(incoming);
		this.setComplete();
	}
	public void testUpdateToSC0percent() throws Exception {
		// 375132559  375133921
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();
        
        incoming.getServiceConnectionAward().setServiceConnectedPercentage(new Integer(0));
		this.getEligibilityEnrollmentService().updateEligibilityData(incoming);
		this.setComplete();
	}		
	public void testUpdateRemoveSC() throws Exception {
		// This test case can force Reject below EGT threshold if veteran
		// has no other eligibilities.
		// 375132559  375133921
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();
        
        incoming.setServiceConnectionAward(null);
		this.getEligibilityEnrollmentService().updateEligibilityData(incoming);
		this.setComplete();
	}
	public void testUpdateWithVerified() throws Exception {
		// 375132559  375133921
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();

        incoming.getEligibilityVerification().setVerificationSource(
        		this.getLookupService().getEligibilityVerificationSourceByCode(EligibilityVerificationSource.CODE_CEV.getCode()));
        this.setEligibilityStatusToVerified(incoming);
		this.getEligibilityEnrollmentService().updateEligibilityData(incoming);
		this.setComplete();
	}
	public void testUpdateIncome() throws Exception {
		// 375132559  375133921
	    PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));        
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();        
    	IncomeTest incomeTest = this.createIncomeTest(
				IncomeTestType.CODE_MEANS_TEST,
				MeansTestStatus.MT_STATUS_MT_COPAY_EXEMPT, new Integer(2010));
    	incoming.setIncomeTest(new Integer(2010), incomeTest);
    	incoming.setFinancialStatement(new Integer(2010),createFinancialStatement());
    	incoming.getFinancialStatement(new Integer(2010)).setAsset(
                this.getLookupService().getAssetTypeByCode(AssetType.CODE_OTHER.getCode()), this.createAsset((double)45458));        
    	incoming.getFinancialStatement(new Integer(2010)).setDebt(this.createDebt((double)5));                
        this.getFinancialsService().updateFinancialAssessment(new Integer(2010), incoming);
		this.setComplete();
	}
	public void testUpdateIncomeMakeCopayReq() throws Exception {
		//375133921 375132559
		PersonIdEntityKeyImpl personKey = new PersonIdEntityKeyImpl(new BigDecimal("375133921"));
        Person tempPerson = this.getPersonService().getPerson(personKey);
        Person incoming = (Person)tempPerson.clone();
        incoming.getFinancialStatement(new Integer(2010)).setAsset(
                this.getLookupService().getAssetTypeByCode(AssetType.CODE_OTHER.getCode()), this.createAsset((double)58));
        incoming.getIncomeTest(new Integer(2010)).setAgreesToPayDeductible(Boolean.TRUE);
        incoming.getIncomeTest(new Integer(2010)).setSendForAdjudication(Boolean.FALSE);
        Map.Entry entry2 = (Map.Entry)  incoming.getFinancialStatement(new Integer(2010)).getIncomes().entrySet().iterator().next();
        Income income  = (Income)entry2.getValue();
        income.setAmount(new BigDecimal("65438"));        
        this.getFinancialsService().updateFinancialAssessment(new Integer(2010), incoming);
		this.setComplete();
	}			
	public void testEligHistory() throws Exception {

		//373975270  373971922 3681316  372474182
		Set changes = this.getEligibilityEnrollmentService().getEligibilityHistoryChangeTimes(
				CommonEntityKeyFactory.createPersonIdEntityKey("375133921"));
		Comparator comparator = new Comparator()
		{
			public int compare(Object pObject1, Object pObject2)
			{
				ChangeEvent event1 = (ChangeEvent)pObject1;
				ChangeEvent event2 = (ChangeEvent)pObject2;
				if (event1 == null || event1.getTimeStamp() == null) return -1;
				if (event2 == null || event2.getTimeStamp() == null) return 1;
				return (event2.getTimeStamp().compareTo(event1.getTimeStamp()));
			}
		};

		List orderedChangeEvents = new ArrayList(changes);
		Collections.sort(orderedChangeEvents, comparator);

		List eventKeys = new ArrayList();

		for (Iterator iter = orderedChangeEvents.iterator(); iter.hasNext();)
		{
			Timestamp time = ((ChangeEvent)iter.next()).getTimeStamp();
			eventKeys.add(gov.va.med.esr.common.util.CommonDateUtils.formatWithTime(time, null));
			System.out.println("change event time=" + time);
		}
		Iterator iter = orderedChangeEvents.iterator();
		ChangeEvent ce = (ChangeEvent)iter.next();
		System.out.println("===============================================================");        
		System.out.println("Person history=" + ce);		
		HistoricalInfo retrieved = this.getEligibilityEnrollmentService().getEligibilityHistoryByChangeTime(ce);        

		System.out.println("Person history info=" + ((Person)retrieved.getEntity()).getServiceConnectionAward().getRatedDisabilities().size());	
		System.out.println("Person service connection =" + ((Person)retrieved.getEntity()).getServiceConnectionAward().getModifiedOn());
		for (Iterator i = ((Person)retrieved.getEntity()).getServiceConnectionAward().getRatedDisabilities().iterator(); i.hasNext();){
			RatedDisability rd = (RatedDisability)i.next();
			System.out.println("type="+rd.getDisability().getCode()+ 
					" modified dt=" + rd.getModifiedOn());
		}
		if (!iter.hasNext()) {
			System.out.println("done");
			return;
		}
		ce = (ChangeEvent)iter.next();
		System.out.println("===============================================================");         	     
		System.out.println("Person history=" + ce);		
		retrieved = this.getEligibilityEnrollmentService().getEligibilityHistoryByChangeTime(ce);     
		System.out.println("Person service connection =" + ((Person)retrieved.getEntity()).getServiceConnectionAward().getModifiedOn());       	
		System.out.println("Person history info=" + ((Person)retrieved.getEntity()).getServiceConnectionAward().getRatedDisabilities().size());	
		for (Iterator i = ((Person)retrieved.getEntity()).getServiceConnectionAward().getRatedDisabilities().iterator(); i.hasNext();){
			RatedDisability rd = (RatedDisability)i.next();
			System.out.println("type="+rd.getDisability().getCode()+ 
					" modified dt=" + rd.getModifiedOn());
		}            	        
	}
	
	public void testEnrollmentHistory() throws Exception {
		//373975270  373971922 3681316  375133921 
		Set changes = this.getEligibilityEnrollmentService().getEligibilityHistoryChangeTimes(
				CommonEntityKeyFactory.createPersonIdEntityKey("375133921"));
		//372474182
		Comparator comparator = new Comparator()
		{
			public int compare(Object pObject1, Object pObject2)
			{
				ChangeEvent event1 = (ChangeEvent)pObject1;
				ChangeEvent event2 = (ChangeEvent)pObject2;
				if (event1 == null || event1.getTimeStamp() == null) return -1;
				if (event2 == null || event2.getTimeStamp() == null) return 1;
				return (event2.getTimeStamp().compareTo(event1.getTimeStamp()));
			}
		};
		List orderedChangeEvents = new ArrayList(changes);
		Collections.sort(orderedChangeEvents, comparator);

		for (Iterator iter = orderedChangeEvents.iterator(); iter.hasNext();) {
			ChangeEvent ce = (ChangeEvent)iter.next();    	
			Timestamp time = ce.getTimeStamp();
			
			System.out.println("change event time=" + time);
			HistoricalInfo retrieved = this.getEligibilityEnrollmentService().getEligibilityHistoryByChangeTime(ce);        
			retrieved = this.getEligibilityEnrollmentService().getEligibilityHistoryByChangeTime(ce);     
			EnrollmentDetermination hist = ((Person)retrieved.getEntity()).getEnrollmentDetermination();
			System.out.println("Enrollment history modified on="+hist.getModifiedOn());
			System.out.println("Person modified on="+((Person)retrieved.getEntity()).getModifiedOn());			
			System.out.println("===============================================================");        
		}
	}
	
	
	
	
	public void testMakeSimplePerson() throws Exception {
		Person onFile = buildSimplePerson(); // bare-bones person
		onFile.setEnrollmentDetermination(this.createEnrollmentDetermination(
				EnrollmentSource.CODE_HEC.getCode(),getDate(2001,1,1), getDate(2001,1,1), VAFacility.CODE_HEC.getCode(), 
				EnrollmentPriorityGroup.GROUP_8.getCode(), 
				EnrollmentPrioritySubGroup.SUBGROUP_D.getCode(),
				EnrollmentStatus.CODE_PENDING_OTHER.getCode()));
		this.savePerson(onFile);
		this.setComplete();
	}
	public void testAddSkelatalPersonFromZ07() throws Exception {
		VAFacility fac = this.getLookupService().getVaFacilityByCode("657");


		Person onFile = this.buildSimplePerson();
		Person incoming = this.savePerson(onFile);
		this.addPermanentAddress(incoming, Calendar.getInstance().getTime(),null);
		VerificationInfo info = new VerificationInfo("x",
				MessageType.CODE_ORUZ07_TO_ESR.getCode(), "x");
		info.setSiteNumber(fac.getCode());
		Person updated = this.getMessagingService().processZ07(incoming, fac,
				info);
		System.out.println("Person id="
				+ updated.getPersonEntityKey().getKeyValueAsString());

		// produced: 375132559
		setComplete();
	}
	
}
