package gov.va.med.esr.service.external;

import gov.va.med.esr.common.builder.entity.FinancialStatementMetaData;
import gov.va.med.esr.common.builder.entity.IncomeTestMetaData;
import gov.va.med.esr.common.builder.entity.metaData.FinancialStatementMetaDataFromIVM;
import gov.va.med.esr.common.builder.entity.metaData.IncomeTestMetaDataFromIVM;
import gov.va.med.esr.common.model.financials.FinancialStatement;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.common.model.financials.PatientVisitSummary;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.messaging.SiteIdentity;
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.service.FinancialsService;
import gov.va.med.esr.service.IVMDMService;
import gov.va.med.esr.service.IVMFinancialInfo;
import gov.va.med.esr.service.external.person.DependentFinancialsInfo;
import gov.va.med.esr.service.external.person.DependentInfo;
import gov.va.med.esr.service.external.person.FinancialStatementInfo;
import gov.va.med.esr.service.external.person.IVMCandidateInfo;
import gov.va.med.esr.service.external.person.IVMLetterInfo;
import gov.va.med.esr.service.external.person.IVMSummary;
import gov.va.med.esr.service.external.person.IncomeTestInfo;
import gov.va.med.esr.service.external.person.IvmLetterCandidateInfo;
import gov.va.med.esr.service.external.person.PersonInfo;
import gov.va.med.esr.service.external.person.SendIVMInfo;
import gov.va.med.esr.service.external.person.SpouseFinancialsInfo;
import gov.va.med.esr.service.external.person.VamcInfo;
import gov.va.med.esr.service.external.person.collections.DependentFinancialsCollection;
import gov.va.med.esr.service.external.person.collections.SpouseFinancialsCollection;
import gov.va.med.esr.service.external.person.collections.VamcDataCollection;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.hl7.InvalidMessageException;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

public class IVMSummaryFactoryImpl implements IVMSummaryFactory{
	private static final Logger logger = Logger.getLogger(IVMSummaryFactoryImpl.class);
	private IVMDMService ivmService;
	private Builder financialStatementBuilder = null;
    private Builder incomeTestBuilder = null;
    private FinancialsService financialsService = null;

	public FinancialsService getFinancialsService() {
		return financialsService;
	}

	public void setFinancialsService(FinancialsService financialsService) {
		this.financialsService = financialsService;
	}

	public  IVMCandidateInfo[] buildIVMCandidatesInfo(Date date) throws ServiceException {
		if(logger.isInfoEnabled())
			logger.info("Calling IVM service to retrieve and update candidates");

		Set candidateSet = null;
		candidateSet = ivmService.findIVMMigrationData(date);

		if(logger.isInfoEnabled())
			logger.info("IVM Candidates retrieved ="+(candidateSet == null ? 0 : candidateSet.size()));

		return ivmService.updateIVMCandidateRetrieval(candidateSet);
	}

	public IvmLetterCandidateInfo[] buildIvmLetterCandidatesInfo()
			throws ServiceException {
		if(logger.isInfoEnabled())
			logger.info("Calling IVM service to retrieve IVM Letter candidates");

		Set letterCandidateSet = null;
		letterCandidateSet = ivmService.findIVMLetterStatusData();

		if(logger.isInfoEnabled())
			logger.info("IVM Letter Candidates retrieved ="+(letterCandidateSet == null ? 0 : letterCandidateSet.size()));

		IvmLetterCandidateInfo[] result = ivmService.updateIVMLetterCandidateRetrieval(letterCandidateSet);
		ivmService.updateCommLogEntriesSentToIVMFlag(letterCandidateSet);
		return result;
	}

	public boolean updateIVMStatus(BigDecimal transactionId, String status) throws ServiceException{
		if(logger.isInfoEnabled())
			logger.info("Calling IVM service to update the retrieved status");

		return ivmService.updateIVMStatus(transactionId, status);

	}

	public PersonInfo applyPersonInfo(Person person, String requestor) {

		PersonInfo personInfo = new PersonInfo();
		if (requestor.equalsIgnoreCase("IVMDATA")) {
			getVeteranData(person, personInfo);
		}
		getVamcData(person, personInfo);
		return personInfo;

	}

	public  IVMSummary processIVMIncomeTest(Person onFile, Integer incomeYear, SendIVMInfo incomingIvmObj,IVMSummary ivmSummary,
			IVMLetterInfo incomingLetterObj){
		if(incomeYear == null || incomeYear == 0 || incomingIvmObj == null){
			ivmSummary.setAcknowledgement("Received with incoming data error");
			ivmSummary.setStatus("failed to continue processing");
			return ivmSummary;
		}
		else{
			try {
				Person incomingPerson = build((Person)onFile.clone(),incomingIvmObj,incomeYear.toString());
				IVMFinancialInfo ivmFinancialInfo = new IVMFinancialInfo();
				ivmFinancialInfo.setIncomeYear(incomeYear);
				ivmFinancialInfo.setIvmActionCode(incomingIvmObj.getIvmActionCode());
				ivmFinancialInfo.setBtFinancialInd(incomingIvmObj.getBtFinancialInd());
				// CodeCR12825 ivm final letters
				if (incomingLetterObj != null) {
					ivmFinancialInfo.setIvmCaseNumber(incomingLetterObj.getIvmCaseNumber());
					ivmFinancialInfo.setIvmLetterCode(incomingLetterObj.getIvmLetterCode());
					ivmFinancialInfo.setIvmCaseClosureDate(incomingLetterObj.getIvmConversionDate());
				}
				this.financialsService.convertOrReverseESRIncomeTest(incomingPerson, ivmFinancialInfo);
			} catch (BuilderException e) {
				ivmSummary.setAcknowledgement("Unable to build an internal ESR income test object with incoming data : " + e.getMessage() );
				ivmSummary.setStatus("Failed");
				return ivmSummary;
			} catch (ServiceException e) {
				ivmSummary.setAcknowledgement("Unable to process incoming data : "+ e.getMessage());
				ivmSummary.setStatus("Failed");
				return ivmSummary;
			}
		}
		ivmSummary.setAcknowledgement("Successfully processed incoming data");
		ivmSummary.setStatus("Success");
		return ivmSummary;
	}

	public Person build(Person input, SendIVMInfo incomingIvmObj, String incomeYear) throws BuilderException
    {
        try
        {
        	Person incomingPerson = input;
        	//FinancialStatementInfo financialStatementInfo = prepareIncomingObject(incomingIvmObj);
        	Integer intIncomeYear = new Integer(incomeYear);


            //this.buildFinancialStatement(incomingPerson, financialStatementInfo, incomeYear);
            this.buildIncomeTest(incomingPerson, incomingIvmObj.getIncomeTest(),incomingIvmObj.getIvmActionCode(),intIncomeYear);

            return incomingPerson;
        } catch (InvalidMessageException e)
        {
            throw new BuilderException(e);
        }
    }

	private FinancialStatementInfo prepareIncomingObject(SendIVMInfo incomingIvmObj){

		FinancialStatementInfo financialStatementInfo = new FinancialStatementInfo();
		int numberOfData = incomingIvmObj.getDependents().getDependent().length;
		DependentFinancialsInfo[] dependentFinancials = new DependentFinancialsInfo[numberOfData];
		List dependentList = Arrays.asList(incomingIvmObj.getDependents().getDependent());
		int index = 0;
		for(Iterator i = dependentList.iterator(); i.hasNext(); index++)
        {
			DependentInfo di =(DependentInfo)i.next();
			DependentFinancialsInfo dfi = new DependentFinancialsInfo();
			dfi.setIncapableOfSelfSupport(di.getIncapableOfSelfSupport());
			dfi.setDependentInfo(di);
			dependentFinancials[index]=dfi;
        }

		DependentFinancialsCollection dependentFinancialsList = new DependentFinancialsCollection(dependentFinancials);

		SpouseFinancialsInfo[] spouseFinancials = new SpouseFinancialsInfo[1];
		SpouseFinancialsInfo sfi = new SpouseFinancialsInfo();
		sfi.setSpouse(incomingIvmObj.getSpouse());
		spouseFinancials[0]= sfi;
		SpouseFinancialsCollection spouseFinancialsList = new SpouseFinancialsCollection(spouseFinancials );

		financialStatementInfo.setDependentFinancialsList(dependentFinancialsList);
		financialStatementInfo.setSpouseFinancialsList(spouseFinancialsList);

		return financialStatementInfo;

	}

	private void buildFinancialStatement(Person person, FinancialStatementInfo financialStatementInfo, String year)
	throws BuilderException, InvalidMessageException
	{
		FinancialStatementMetaData metaData = new FinancialStatementMetaDataFromIVM (financialStatementInfo, year);
		Integer incomeYear = new Integer(metaData.getIncomeYear());

		//		Remove all existing financial statements and add the one for the
		//		income year in message
		person.removeAllFinancialStatements();

		FinancialStatement financialStatement = (FinancialStatement) financialStatementBuilder
		.build(metaData);
		if (incomeYear != null)
		{
			person.setFinancialStatement(incomeYear, financialStatement, true);
		}

	}

	private void buildIncomeTest(Person person, IncomeTestInfo incomeTestInfo, String actionCode, Integer year)
	throws BuilderException, InvalidMessageException
	{

		IncomeTestMetaData incomeTestMetadata = new IncomeTestMetaDataFromIVM(incomeTestInfo,actionCode, year);

		Integer incomeYear = new Integer(incomeTestMetadata.getIncomeYear());

		if(incomeYear !=null){
			incomeTestMetadata.setEntity(person.getIncomeTest(incomeYear));
		}

		IncomeTest incomeTest = (IncomeTest) this.incomeTestBuilder
		.build(incomeTestMetadata);

		//Remove all existing income tests and add the one for the income year
		//in message
		person.removeAllIncomeTests();


		if (incomeYear != null)
		{
			person.setIncomeTest(incomeYear, incomeTest);
		}
	}

	private void getVamcData(Person person, PersonInfo personInfo){
		Set sites = new HashSet();
		if(person.getSiteIdentities() != null){
			sites = person.getSiteIdentities();
		}
		VamcInfo[] vamc = new VamcInfo[sites.size()];
		int i = 0;
        for (Iterator iter = sites.iterator(); iter.hasNext();) {
        	vamc[i] = getVAMCIdData(person, (SiteIdentity) iter.next());
            i++;
        }
        if(vamc.length > 0){
        	personInfo.setVamcData(new VamcDataCollection(vamc));
        }

	}

	private VamcInfo getVAMCIdData(Person person, SiteIdentity siteIdentity) {
        VamcInfo vamcData = new VamcInfo();
        VAFacility facility = siteIdentity.getVaFacility();
        vamcData.setFacilityNumber(facility.getStationNumber() == null ? null : facility.getStationNumber());
        vamcData.setDfnNumber(siteIdentity.getDfn() == null ? null : siteIdentity.getDfn());
        PatientVisitSummary summary = PatientVisitSummary.getLastestVisitedSummary(person
                .getPatientVisitSummaries(facility));
        vamcData.setLastVisitDate(summary == null ? null : summary.getLastVisitDate());
        vamcData.setVamcReportDate(summary == null ? null : summary.getModifiedOn());

        return vamcData;
    }


	public IVMDMService getIvmService() {
		return ivmService;
	}

	public void setIvmService(IVMDMService ivmService) {
		this.ivmService = ivmService;
	}

	private void getVeteranData(Person person, PersonInfo personInfo) {

	    addNameData(personInfo, person.getLegalName());
	    SSN ssn = person.getOfficialSsn();
	    addSsnTextData(personInfo, ssn);

	    BirthRecord dob = person.getBirthRecord();
	    personInfo.setGender(person.getGender() == null ? null : person.getGender().getName());
	    personInfo.setDob(dob == null ? null : dob.getBirthDate() == null ? null : dob.getBirthDate().getStandardFormat());
	    addSsnStatusData(personInfo, ssn);
	}

	private void addSsnStatusData(PersonInfo personInfo, SSN ssn) {
	    SSAVerificationStatus ssaVerStatus = ssn == null ? null : ssn.getSsaVerificationStatus();
	    personInfo.setSsaVerificationStatus(ssaVerStatus == null ? null : ssaVerStatus.getDescription());
	    personInfo.setSsaVerificationDate(ssn == null ? null : ssn.getSsaVerificationDate());

	}

	private void addSsnTextData(PersonInfo personInfo, SSN ssn) {
	    String ssnText = ssn == null ? null : ssn.getSsnText();
	    ssnText = ssnText == null ? null : ssnText.replaceAll("-", "");
	    personInfo.setSsnText(ssnText);
	}

	private void addNameData(PersonInfo personInfo, Name name) {
		personInfo.setLastName(name == null ? null : name.getFamilyName());
		personInfo.setFirstName(name == null ? null : name.getGivenName());
		personInfo.setMiddleName(name == null ? null : name.getMiddleName());
	    personInfo.setPrefix(name == null ? null : name.getPrefix());
	    personInfo.setSuffix(name == null ? null : name.getSuffix());
	}


	public Builder getFinancialStatementBuilder() {
		return financialStatementBuilder;
	}

	public void setFinancialStatementBuilder(Builder financialStatementBuilder) {
		this.financialStatementBuilder = financialStatementBuilder;
	}

	public Builder getIncomeTestBuilder() {
		return incomeTestBuilder;
	}

	public void setIncomeTestBuilder(Builder incomeTestBuilder) {
		this.incomeTestBuilder = incomeTestBuilder;
	}

}
