/********************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.esr.common.batchprocess;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;

import org.apache.commons.lang.Validate;

import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKeyImpl;
import gov.va.med.esr.common.model.ee.EligibilityVerification;
import gov.va.med.esr.common.model.lookup.AACIndicator;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;
import gov.va.med.esr.common.model.lookup.ComMailingStatusType;
import gov.va.med.esr.common.model.lookup.MessageType;
import gov.va.med.esr.service.CommsLetterRequestService;
import gov.va.med.esr.service.GenerateQRYZ11MessagingService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.PersonHelperService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.CommsEmailBulletinService;
import gov.va.med.esr.service.impl.GenerateQRYZ11MessagingServiceImpl;
import gov.va.med.fw.batchprocess.AbstractDataQueryIncrementalProcess;
import gov.va.med.fw.batchprocess.BatchProcessService;
import gov.va.med.fw.batchprocess.DataProcessCompletedHandler;
import gov.va.med.fw.batchprocess.DataQueryProcessExecutionContext;
import gov.va.med.fw.batchprocess.ProcessStatisticsHandler;
import gov.va.med.fw.rule.RuleException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.batchprocess.model.JobConfig;
import gov.va.med.fw.io.writer.FormattedFileWriter;
import gov.va.med.esr.common.model.financials.IncomeTest;
import gov.va.med.esr.service.trigger.LetterTrigger;
import gov.va.med.esr.service.trigger.LetterTriggerEvent;
import gov.va.med.esr.service.trigger.LetterTriggerIdentity;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;
import gov.va.med.esr.common.model.lookup.ComMailingTriggerType;
import org.apache.commons.lang.StringUtils;
/**
 * VFA-SP1 Letter 680N - One Time Notification of Networth Discontinuation
 * Selection Criteria: Veterans not deceases
 * Letter not yet sent
 * Latest Means Test reflect income less deductible expenses below the Means Test threshold,
 * Income less deductible expense plus net worth greater than or equal to $80,000
 */
public class Trigger680NLetterNetWorthDiscontinuation extends AbstractDataQueryIncrementalProcess {

    private PersonService personService;
    private LookupService lookupService;  
    private CommsLetterRequestService letterRequestService = null;
	private PersonHelperService personHelperService;
	private ComLetterTemplateType formNumber = null;
	protected static final BigDecimal ZERO_AMOUNT = new BigDecimal(0);
	private IncomeTest currentIncomeTest = null;
	
    protected void processData(DataQueryProcessExecutionContext context, List acquiredData)  {
        if(logger.isDebugEnabled())
            logger.debug(getProcessName() + ": Query increment result Size="+(acquiredData == null ? 0 : acquiredData.size()));
        
        if (acquiredData == null)
            return;
        /*
        try{
        	letterRequestService = (CommsLetterRequestService) getComponent("commsLetterRequestService");
        }catch (ServiceException ex){
        	return;
        }
        */
        
        // TODO it should be FORM_NUMBER_680N
        try{
        	this.formNumber = getComLetterTemplateType(ComLetterTemplateType.FORM_NUMBER_680N.getName());
        } catch (RuleException ex){
        	return;
        }
        if ( this.formNumber==null) return;
        
        // Add check for isInterrupted so don't have to wait for entire batch to finish
        for (int i = 0; i < acquiredData.size() && !isInterrupted(context); i++) {
            // Object[] returned from get when scrolling (idempotent is false)
            Object[] row = (Object[]) acquiredData.get(i);
            BigDecimal personId = (BigDecimal) row[0];
            
            PersonEntityKey key = new PersonIdEntityKeyImpl(personId);
            
            if(logger.isDebugEnabled())
                logger.debug("Processing person # " + (i+1) + " with id = " + personId);
            
            try {
               processRecord(key, row);
           	   if ( currentIncomeTest!=null && IsSendLetter680N(currentIncomeTest))
           		   context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
            } catch (Exception ex) {
                context.getProcessStatistics().incrementNumberOfErrorRecords();
                String errMsg = "Error while executing " + getProcessName() + " for person "
                                + personId;
                context.getExceptionData().add(errMsg+ " Reason: "+ ex.getMessage());
                if(logger.isWarnEnabled())
                    logger.warn(errMsg + " Reason: ", ex);
            }
            
            // Update statistics more frequently than once per batch (default size 500)
            if(context.getProcessStatistics().isTotalNumberMod(DEFAULT_JOB_RESULT_UPDATE_INTERVAL))
                this.updateJobResult(context);
        }
        
        if(logger.isDebugEnabled()) {
            logger.debug(getProcessName() + ": Processing of current batch complete.");
            logger.debug(getProcessName() + ": Successful records count = "+context.getProcessStatistics().getNumberOfSuccessfulRecords());
            logger.debug(getProcessName() + ": Failure records count ="+context.getProcessStatistics().getNumberOfErrorRecords());
        }
    }	

    /**
     * Processes data for a particular person
     * @param key
     * @param VPID
     * @throws ServiceException 
     */
    protected void processRecord(PersonEntityKey key, Object[] dataRow) throws Exception 
    {
        String VPID = (String) dataRow[1];
		Person person = personService.getPerson(key);
		this.currentIncomeTest = null;
		
		if (person == null)
			throw new RuntimeException("Unable to find Person for VPID: "+ VPID);
		
		this.currentIncomeTest=personHelperService.getCurrentIncomeTest(person);
		
		if ( currentIncomeTest!=null && IsSendLetter680N(currentIncomeTest))
			letterRequestService.requestAacLetter(person, new LetterTriggerIdentity(this.formNumber, LetterTrigger.CategoryType.VETERAN_LETTER), null, LetterTriggerEvent.MANUAL_MAIL, null);	
    }

    private boolean IsSendLetter680N(IncomeTest it){
    	boolean sendLetter680Nflag=false;
    	BigDecimal mtThreshold;
    	BigDecimal totalIncome;
    	BigDecimal netWorth;
    	BigDecimal networthThreshold;
    	BigDecimal deductibleExpenses;
    	BigDecimal totalNetIncome;
    	BigDecimal totalNetIncomeandNetworth;
    	
    	if (it!=null) {
    		// it.getNetIncome();
    		mtThreshold = getNotNull(it.getThresholdA());
    		totalIncome = getNotNull(it.getTotalIncome());
    		netWorth = getNotNull(it.getNetWorth());
    		networthThreshold = new BigDecimal(80000);
    		deductibleExpenses = getNotNull(it.getDeductibleExpenses());
    		totalNetIncome = getNotNull(totalIncome.compareTo(deductibleExpenses)>0 ? totalIncome.subtract(deductibleExpenses):ZERO_AMOUNT); //income less deductible expenses
    		totalNetIncomeandNetworth = getNotNull(totalNetIncome.add(netWorth)); 
    		if (totalNetIncome.compareTo(mtThreshold) < 0  && totalNetIncomeandNetworth.compareTo(networthThreshold) >=0 )
    			sendLetter680Nflag = true;
    	}
    	return sendLetter680Nflag;
    }
  
    private BigDecimal getNotNull(BigDecimal bd) {
        return bd == null ? new BigDecimal(0) : bd;
     }
    
    private ComLetterTemplateType getComLetterTemplateType(String type) throws RuleException {
    	if (type != null) 
    	{
    		try {
    			return this.getLookupService().getComLetterTemplateTypeByCode(type);
    		} catch (ServiceException e) {
    			throw new RuleException( "Failed to get com letter template type", e);
    		}
    	}
    	return null;
    }
    /* letterRequestService
     * 
     */
    public CommsLetterRequestService getLetterRequestService() {
		return letterRequestService;
	}
    
	public void setLetterRequestService(CommsLetterRequestService letterRequestService) {
		this.letterRequestService = letterRequestService;
	}

    /**
	 * @param personService
	 *            The personService to set.
	 */
	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}
	
    public PersonService getPersonService() {
		return personService;
	}
    /**
     * @return Returns the lookupService.
     */
    public LookupService getLookupService() {
        return lookupService;
    }
    /**
     * @param lookupService The lookupService to set.
     */
    public void setLookupService(LookupService lookupService) {
        this.lookupService = lookupService;
    }    
	 /**
     * @return Returns the personHelperService.
     */
    public PersonHelperService getPersonHelperService() {
        return personHelperService;
    }
    /**
     * @param personHelperService The personHelperService to set.
     */
    public void setPersonHelperService(PersonHelperService personHelperService) {
        this.personHelperService = personHelperService;
    }
    
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        Validate.notNull(personService);
        Validate.notNull(lookupService);
        Validate.notNull(personHelperService);
        Validate.notNull(letterRequestService);   
    }
}
