package gov.va.med.esr.voa.validator;

import java.math.BigDecimal;

import gov.va.med.esr.common.model.lookup.AddressType;
import gov.va.med.esr.common.model.lookup.AssetType;
import gov.va.med.esr.common.model.lookup.EmploymentStatus;
import gov.va.med.esr.common.model.lookup.IncomeType;
import gov.va.med.esr.common.model.lookup.Relationship;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.util.AbstractCommonTestCase;
import gov.va.med.esr.voa.common.ErrorCode;
import gov.va.med.esr.voa.webservice.AddressInfo;
import gov.va.med.esr.voa.webservice.AssetCollection;
import gov.va.med.esr.voa.webservice.AssetInfo;
import gov.va.med.esr.voa.webservice.DependentFinancialsCollection;
import gov.va.med.esr.voa.webservice.DependentFinancialsInfo;
import gov.va.med.esr.voa.webservice.DependentInfo;
import gov.va.med.esr.voa.webservice.EmploymentInfo;
import gov.va.med.esr.voa.webservice.ExpenseCollection;
import gov.va.med.esr.voa.webservice.ExpenseInfo;
import gov.va.med.esr.voa.webservice.FinancialStatementInfo;
import gov.va.med.esr.voa.webservice.FinancialsInfo;
import gov.va.med.esr.voa.webservice.IncomeCollection;
import gov.va.med.esr.voa.webservice.IncomeInfo;
import gov.va.med.esr.voa.webservice.ObjectFactory;
import gov.va.med.esr.voa.webservice.SpouseFinancialsCollection;
import gov.va.med.esr.voa.webservice.SpouseFinancialsInfo;
import gov.va.med.esr.voa.webservice.SpouseInfo;
import gov.va.med.esr.voa.webservice.SsnCollection;
import gov.va.med.esr.voa.webservice.SsnInfo;

import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;

public class FinancialInfoValidatorTest extends AbstractCommonTestCase {

	private FinancialInfoValidator validator;

	private FinancialsInfo financialsInfo;

	@Override
	public void onSetUpInTransaction() throws Exception {
		super.onSetUpInTransaction();
		validator = new FinancialInfoValidator();
		validator.setLookupService(getLookupService());

		ObjectFactory factory = new ObjectFactory();
		financialsInfo = factory.createFinancialsInfo();

		FinancialStatementInfo financialStatementInfo = factory
				.createFinancialStatementInfo();
		financialsInfo.setFinancialStatement(financialStatementInfo);

		SpouseFinancialsCollection spouseFinancialsCollection = factory
				.createSpouseFinancialsCollection();
		financialStatementInfo
				.setSpouseFinancialsList(spouseFinancialsCollection);

		SpouseFinancialsInfo spouseFinancialsInfo = factory
				.createSpouseFinancialsInfo();
		spouseFinancialsCollection.getSpouseFinancials().add(
				spouseFinancialsInfo);

		SpouseInfo spouseInfo = factory.createSpouseInfo();
		spouseFinancialsInfo.setLivedWithPatient(Boolean.FALSE);
		spouseFinancialsInfo.setSpouse(spouseInfo);

		spouseInfo.setDob("02/12/1966");
		spouseInfo.setFamilyName("sun");
		spouseInfo.setGivenName("test");
		spouseInfo.setGender("male");
		spouseInfo.setMaidenName("maidenName");
		spouseInfo.setMiddleName("middleName");
		spouseInfo.setRelationship("brother");
		SsnInfo ssnInfo = factory.createSsnInfo();
		ssnInfo.setSsnText("123456789");
		ssnInfo.setType(SSNType.CODE_ACTIVE.getCode());
		SsnCollection ssnCollection = factory.createSsnCollection();
		ssnCollection.getSsn().add(ssnInfo);
		spouseInfo.setSsns(ssnCollection);
		spouseInfo.setStartDate("12/12/1988");

		AddressInfo addressInfo = factory.createAddressInfo();
		spouseInfo.setAddress(addressInfo);
		addressInfo.setLine1("Address Line 1");
		addressInfo.setLine2("Address Line 2");
		addressInfo.setLine3("Address Line 3");
		addressInfo.setCity("Plano");
		addressInfo.setState("TX");
		addressInfo.setCountry("USA");
		addressInfo.setZipCode("75024");
		addressInfo.setAddressTypeCode(AddressType.CODE_PERMANENT_ADDRESS
				.getCode());
		addressInfo.setPhoneNumber("2140009999");
		
		EmploymentInfo employmentInfo = factory.createEmploymentInfo();
		spouseInfo.setEmployment(employmentInfo);
		employmentInfo.setEmploymentStatus(EmploymentStatus.CODE_FULL_TIME.getCode());
		employmentInfo.setEmployerName("Boss");
		employmentInfo.setEmployerPhone("12142223333");
		
		AddressInfo employmentAddress = factory.createAddressInfo();
		employmentInfo.setEmployerAddress(employmentAddress);
		employmentAddress.setLine1("122222 main");
		employmentAddress.setCity("Coppell");
		employmentAddress.setState("TX");
		employmentAddress.setCountry("USA");		
		employmentAddress.setZipCode("75001");
		employmentAddress.setPhoneNumber("");
		employmentAddress.setZipPlus4("1234");

		IncomeCollection incomeCollection = factory.createIncomeCollection();
		IncomeInfo incomeInfo = factory.createIncomeInfo();
		incomeCollection.getIncome().add(incomeInfo);
		spouseFinancialsInfo.setIncomes(incomeCollection);

		incomeInfo.setAmount(new BigDecimal(12345));
		incomeInfo.setType(IncomeType.INCOME_TYPE_TOTAL_INCOME_FROM_EMPLOYMENT
				.getCode());

		AssetCollection assetCollection = factory.createAssetCollection();
		spouseFinancialsInfo.setAssets(assetCollection);
		AssetInfo assetInfo = factory.createAssetInfo();
		assetCollection.getAsset().add(assetInfo);

		assetInfo.setAmount(new BigDecimal(1234));
		assetInfo.setAssetType(AssetType.CODE_REAL_ESTATE.getCode());

		DependentFinancialsCollection dependentFinancialsCollection = factory
				.createDependentFinancialsCollection();
		financialStatementInfo
				.setDependentFinancialsList(dependentFinancialsCollection);
		DependentFinancialsInfo dependentFinancialsInfo = factory
				.createDependentFinancialsInfo();
		DependentInfo dependentInfo = factory.createDependentInfo();
		dependentFinancialsInfo.setDependentInfo(dependentInfo);
		dependentFinancialsCollection.getDependentFinancials().add(
				dependentFinancialsInfo);

		dependentInfo.setDob("01/01/1960");
		dependentInfo.setFamilyName("test");
		dependentInfo.setGivenName("test");
		dependentInfo.setMiddleName("test");
		dependentInfo.setRelationship(Relationship.CODE_BROTHER.getCode());
		SsnInfo ssnInfo2 = factory.createSsnInfo();
		ssnInfo2.setSsnText("123456789");
		ssnInfo2.setType(SSNType.CODE_ACTIVE.getCode());
		SsnCollection depSsnCollection = factory.createSsnCollection();
		depSsnCollection.getSsn().add(ssnInfo2);
		spouseInfo.setSsns(depSsnCollection);

		dependentInfo.setSsns(ssnCollection);
		dependentInfo.setStartDate("01/01/2001");
		dependentInfo.setDob("01/01/2001");
		dependentFinancialsInfo.setIncapableOfSelfSupport(Boolean.TRUE);

		ExpenseCollection expenseCollection = factory.createExpenseCollection();
		dependentFinancialsInfo.setExpenses(expenseCollection);
		ExpenseInfo expenseInfo = factory.createExpenseInfo();
		expenseCollection.getExpense().add(expenseInfo);
		expenseInfo.setAmount(new BigDecimal(123));

		IncomeCollection incomeCollection2 = factory.createIncomeCollection();
		IncomeInfo incomeInfo2 = factory.createIncomeInfo();
		incomeInfo2.setAmount(new BigDecimal(12345));
		incomeInfo2.setType(IncomeType.INCOME_TYPE_TOTAL_INCOME_FROM_EMPLOYMENT
				.getCode());
		incomeCollection2.getIncome().add(incomeInfo2);
		dependentFinancialsInfo.setIncomes(incomeCollection2);

		AssetCollection assetCollection2 = factory.createAssetCollection();
		dependentFinancialsInfo.setAssets(assetCollection2);
		dependentFinancialsInfo.setLivedWithPatient(Boolean.TRUE);
	}

	@Override
	public void onTearDownInTransaction() {
		validator = null;
		financialsInfo = null;
		super.onTearDownInTransaction();
	}

	public void testFinancialsInfo() throws Exception {
		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertFalse(errors.hasErrors());
	}

	public void testSpouse() throws Exception {
		FinancialStatementInfo financialStatementInfo = financialsInfo
				.getFinancialStatement();
		SpouseFinancialsCollection spouseFinancialsCollection = financialStatementInfo
				.getSpouseFinancialsList();
		SpouseFinancialsInfo spouseFinancialsInfo = spouseFinancialsCollection
				.getSpouseFinancials().iterator().next();
		spouseFinancialsInfo.setLivedWithPatient(null);

		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		SpouseInfo spouseInfo = spouseFinancialsInfo.getSpouse();
		spouseInfo.setFamilyName(null);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(2, errors.getErrorCount());

		spouseInfo
				.setFamilyName("long family name 12345456667777787899012343564675768");

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(2, errors.getErrorCount());

		spouseInfo.setDob("12/2222");
		SsnInfo ssnInfo = spouseInfo.getSsns().getSsn().iterator().next();
		ssnInfo.setSsnText("122");

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(4, errors.getErrorCount());
	}

	public void testSpouseEmployment() throws Exception {

	}

	public void testSpouseAddress() throws Exception {
		FinancialStatementInfo financialStatementInfo = financialsInfo
				.getFinancialStatement();
		SpouseFinancialsCollection spouseFinancialsCollection = financialStatementInfo
				.getSpouseFinancialsList();
		SpouseFinancialsInfo spouseFinancialsInfo = spouseFinancialsCollection
				.getSpouseFinancials().iterator().next();
		SpouseInfo spouseInfo = spouseFinancialsInfo.getSpouse();
		AddressInfo addressInfo = spouseInfo.getAddress();
		addressInfo.setLine1("1234567890qwertyuiopasdfghjkl 1233243242343242");
		addressInfo.setCity(null);
		addressInfo.setState(null);
		addressInfo.setCountry("USA");
		addressInfo.setZipCode(null);
		addressInfo.setPhoneNumber("aBB3981234");

		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(5, errors.getErrorCount());

		addressInfo.setState("invalid");
		addressInfo.setZipCode("111");
		addressInfo.setPhoneNumber("123");

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(5, errors.getErrorCount());
	}

	public void testSpouseIncome() throws Exception {
		FinancialStatementInfo financialStatementInfo = financialsInfo
				.getFinancialStatement();
		SpouseFinancialsCollection spouseFinancialsCollection = financialStatementInfo
				.getSpouseFinancialsList();
		SpouseFinancialsInfo spouseFinancialsInfo = spouseFinancialsCollection
				.getSpouseFinancials().iterator().next();
		IncomeInfo incomeInfo = spouseFinancialsInfo.getIncomes().getIncome()
				.iterator().next();
		incomeInfo.setAmount(null);

		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		incomeInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		incomeInfo
				.setType(IncomeType.INCOME_TYPE_FARM_RANCH_PROPERTY_OR_BUSINESS_INCOME
						.getCode());
		incomeInfo.setAmount(null);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		incomeInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		incomeInfo.setType(IncomeType.INCOME_TYPE_TOTAL_ALL_OTHER_INCOME
				.getCode());
		incomeInfo.setAmount(null);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		incomeInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());
	}

	public void testSpouseAsset() throws Exception {
		FinancialStatementInfo financialStatementInfo = financialsInfo
				.getFinancialStatement();
		SpouseFinancialsCollection spouseFinancialsCollection = financialStatementInfo
				.getSpouseFinancialsList();
		SpouseFinancialsInfo spouseFinancialsInfo = spouseFinancialsCollection
				.getSpouseFinancials().iterator().next();
		AssetInfo assetInfo = spouseFinancialsInfo.getAssets().getAsset()
				.iterator().next();
		assetInfo.setAmount(null);

		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		assetInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		assetInfo.setAssetType(AssetType.CODE_CASH.getCode());
		assetInfo.setAmount(null);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		assetInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());

		assetInfo.setAssetType(AssetType.CODE_OTHER.getCode());
		assetInfo.setAmount(null);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		boolean hasError0217 = contain(errors, ErrorCode.VOA_0217);
		assertTrue(hasError0217);

		assetInfo.setAmount(new BigDecimal(1000000000000L));

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(1, errors.getErrorCount());
	}

	public void testDependentFinancialInfo() {
		FinancialStatementInfo financialStatementInfo = financialsInfo
				.getFinancialStatement();
		DependentFinancialsInfo dependentFinancialsInfo = financialStatementInfo
				.getDependentFinancialsList().getDependentFinancials()
				.iterator().next();
		DependentInfo dependentInfo = dependentFinancialsInfo
				.getDependentInfo();

		dependentInfo.setFamilyName(null);
		dependentInfo.setGivenName(null);
		dependentInfo
				.setMiddleName("1234324324324324234234234234234234234324234324fdsdfg");
		dependentInfo.setRelationship(null);
		dependentInfo.setStartDate(null);
		dependentInfo.setDob(null);

		dependentFinancialsInfo.setIncapableOfSelfSupport(null);
		dependentFinancialsInfo.setLivedWithPatient(null);

		BindException errors = new BindException(financialsInfo,
				"financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(8, errors.getErrorCount());

		dependentInfo.setStartDate("01/01/2022");
		dependentInfo.setDob("01/01/2022");

		dependentFinancialsInfo.setIncapableOfSelfSupport(Boolean.TRUE);
		dependentFinancialsInfo.setLivedWithPatient(Boolean.TRUE);

		errors = new BindException(financialsInfo, "financialsInfo");
		validator.validate(financialsInfo, errors);

		assertEquals(6, errors.getErrorCount());
	}
	
	private boolean contain(BindException errors, final String targetCode) {
		boolean test = false;
		for (Object iter : errors.getAllErrors()) {
			ObjectError error = (ObjectError) iter;
			String code = error.getCode();
			if (targetCode.equals(code)) {
				test = true;
			}
		}
		return test;
	}
}
