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

import gov.va.med.esr.common.persistent.comms.CommsTemplateDAO;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.Validate;

import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.fw.batchprocess.AbstractDataFileSingleRowIncrementProcess;
import gov.va.med.fw.batchprocess.DataFileProcessExecutionContext;
import gov.va.med.fw.batchprocess.HandbookMailingResponseCode1RejectFileProcessStatistics;
import gov.va.med.fw.batchprocess.ProcessStatistics;
import gov.va.med.esr.common.model.comms.HandBookMailQueue;
import gov.va.med.esr.common.model.comms.HandBookMailStatus;
import gov.va.med.esr.common.model.lookup.ComAACRejectReasonType;
import gov.va.med.esr.common.model.lookup.HandBookMailStatusType;
import gov.va.med.esr.service.CommsLogService;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.esr.service.HandBookService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.common.batchprocess.HandbookMailingResponseCode1RejectFileData;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;



/** CCR10962
 * Batch process that reads from incoming CMS address file parsing
 * successful mailings of hankd books
 * 
 * TODO: use good data - database data is not allowing Person objects to be used
 * 
 * @author DNS   PICKLJ
 *
 *
 */
public class HandbookMailingResponseCode1RejectFileProcess extends
		AbstractDataFileSingleRowIncrementProcess {
	
	protected PersonService personService;
	private HandBookService handBookService;
	private LookupService lookupService;
	private DemographicService demographicService;
	private CommsLogService commsLogService;
	private CommsTemplateDAO templDAO;
	private String rawData = null;
	private HandbookMailingResponseCode1RejectFileProcessStatistics stats;
	
	/* * Sudha email 07212001 - Failed file – records that fail the validation checks in ICD need 
     * not be written to exception file
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.batchprocess.AbstractDataProcess#processData(gov.va.med.fw.batchprocess.DataProcessExecutionContext,
	 *      java.util.List)
	 */
	public  void processDataRecords(
			      DataFileProcessExecutionContext context, List acquiredData) {
		if(acquiredData.isEmpty()) {
			logger.info("no records"); 
			return;
		}	
		logger.info("processing a new record"); 
		if (stats == null ) { 
		      try {		
		          stats = (HandbookMailingResponseCode1RejectFileProcessStatistics)context.getProcessStatistics();
		      } catch (java.lang.ClassCastException cex) {
	              logger.error("ClassCastException crap! : ", cex);
		      }	  
		}		
			
	        for (int i=0;i<acquiredData.size();i++) {
		     try {
	        	Object obj = acquiredData.get(i);
	            // if no exception continue reading file data
			    if (processDataRecord(context, obj)) {

				    if (isKeepProcessedData()) {
					  context.getProcessedData().add(obj);
				    } else {
					  logger.info("NO MORE DATA run any clean up");	
					  updateJobResultsLast(context);
				    }
				  
			    } else {
				  // some error while calling processDataRecord so stop
				  logger.info("one record sent back false - stopping processDataRecords"); 
				  updateJobResultsLast(context);
				  break;				  
			    }
			  } catch (RuntimeException e) {
					if(logger.isErrorEnabled())
					logger.error("RuntimeException processDataRecords^"+e.getMessage()+"^"+rawData);
					context.getExceptionData().add(createExceptionObject("RuntimeException processDataRecords^"+rawData+"^"+e.fillInStackTrace()));
			  }
			} 
	}	
	
	
	protected boolean processDataRecord(DataFileProcessExecutionContext context, Object bean) {
		
		HandbookMailingResponseCode1RejectFileData dataRecord = (HandbookMailingResponseCode1RejectFileData) bean;
		boolean success = true;
        this.rawData = context.getCurrentRowRawData();
		try {			
			// validate record
			// Missing Required fields
			if (dataRecord.validateData().size() > 0) {
				// collect error info
				List invalidData = dataRecord.validateData();
				String errMsg = "";
				for (int i=0;i<invalidData.size();i++) {
					errMsg = errMsg+"^"+(String)invalidData.get(i);
				}				
				logger.error("Failed - Missing Required Fields"+errMsg);
				context.getExceptionData().add(createExceptionObject("Failed - Missing Required Fields"+errMsg+"^"+rawData));
				stats.incrementNumberOfErrorRecords();
				// keep processing?
				return success;
			}
            /*
             * SUC62.4 For each record received on this file the system will update the 
             * Communication Status to Reject By AAC or Reject by CMS for handbook
             * SUC62.4.1 The system captures the Date/Time Received
             * SUC62.4.2 The system sets the Date/Time Updated to the date/time the Communication Status was set.
             * SUC62.4.3 The system updates the Code 1 Reject Reason with the code received with each record. 
             */			
			// Invalid Product ID
			String formName = dataRecord.getProdNumText();
			// check Product ID update stats//H400H, H400B, H400F	
			if (formName.equals("H400H")) {
					stats.incrementH400HRecordsProcessed();
			} else if (formName.equals("H400B")) {
					stats.incrementH400FRecords();
			} else if (formName.equals("H400F")) {
					stats.incrementH400FRecords();				
			} else {
					logger.info("Invalid Product ID^"+rawData);
					context.getExceptionData().add(createExceptionObject("Invalid Product ID^"+rawData));
					context.getProcessStatistics().incrementNumberOfErrorRecords();
					// keep processing?
					return success;					
			}				
			addReason(dataRecord.getProdNumText(),dataRecord.getReject());
			// find mailQueue 
			HandBookMailQueue mailQueue = new HandBookMailQueue();
			try {
				 mailQueue = handBookService.findHandBookByIdentifier(dataRecord.getUID());
			} catch (Exception ex) {
			     logger.error("Invalid Request ID^Exception - handBookService.findHandBookByIdentifier^"+ex.getMessage()+"^"+rawData);
				 context.getExceptionData().add("Invalid Request ID^Exception - handBookService.findHandBookByIdentifier^"+rawData+"^"+ex.fillInStackTrace());
				 stats.incrementNumberOfErrorRecords();
				 // keep processing?
				 return success;	
			}
            if (mailQueue == null) {
			     logger.error("Invalid Request ID^mailQueue is null^"+rawData);
				 context.getExceptionData().add("Invalid Request ID^mailQueue is null^"+rawData);
				 // keep processing?
				 return success;            	
            }		
			// VPID not matching the one sent in the request
			// there is no VPID in mailQueue but we can get VPID from create personService
			// failure to create is Invalid Veteran Id	
			String vpidCompare = null;
			String icnCompare = null;
			try {
				String personId = String.valueOf(mailQueue.getPersonId());
				PersonIdEntityKey pkey = CommonEntityKeyFactory.createPersonIdEntityKey(personId); 
				vpidCompare = (personService.getVPIDByPersonId(pkey)).getVPID();
				icnCompare  = handBookService.getICNChecksumForVpid(vpidCompare);
				
				logger.info("does ["+dataRecord.getVPID()+"] = ["+icnCompare+"]");
			} catch (Exception ex) {
				logger.error("Exception - getVPIDByPersonId failed^"+rawData+"^"+ex.fillInStackTrace());
				context.getExceptionData().add("Exception - getVPIDByPersonId failed^"+rawData+"^"+ex.fillInStackTrace());
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing records?				
				return success; 				
			}			          
            // match icnCompare
			if (!icnCompare.equals(dataRecord.getVPID())) {
				logger.error("Invalid Veteran ID^"+rawData);
				context.getExceptionData().add("Invalid Veteran Id^"+rawData);
				context.getProcessStatistics().incrementNumberOfErrorRecords();
				// keep processing records?				
				return success; 				
			}
            // update failed reason
            ComAACRejectReasonType reasonType = null;
            try {
            	// reason code is 1 char
            	String tempReason = dataRecord.getReject();
            	if (tempReason.length()>1) tempReason = tempReason.substring(0, 1);
            	reasonType = lookupService.getComAACRejectReasonTypeByCode(tempReason);
            } catch (Exception ex) {
            	logger.error("Exception - lookupService getComAACRejectReasonTypeByCode failed^"+rawData+"^"+ex.fillInStackTrace());
            	context.getExceptionData().add("Exception - lookupService getComAACRejectReasonTypeByCode failed^"+rawData+"^"+ex.fillInStackTrace());
            	context.getProcessStatistics().incrementNumberOfErrorRecords();
            	// keep processing?
			    return success;
            }
			// update status			
			// stub - update Reject by CMS in go get a HandbookMailQueue record using uid
			// if update is true then we update Bad Address Reason		
            String uid = dataRecord.getUID();
            try {
            	HandBookMailStatus status = mailQueue.getHandBookMailStatus();           	
            	// update status  "Mailed By CMS"  
            	HandBookMailStatusType statusType  =
                	lookupService.getHandBookMailingStatusTypeByCode(HandBookMailStatusType.REJECTED_ADDRESS_BY_CMS.getCode());
            	status.setStatusType(statusType);
            	// update reject reason
                mailQueue.getHandBookMailStatus().setRejectReasonType(reasonType);
                mailQueue.getHandBookMailStatus().setErrorText(reasonType.getDescription());
            	handBookService.saveHandbookMailStatus(mailQueue, statusType);
            	
            	// trigger ILOG
            	// Comment out triggering ILOG for CCR11864
                //this.handBookService.handleMailingResponse(mailQueue);

            } catch (Exception ex) {
    			logger.error("processDataRecord updateStatus update Exception uid="+uid+" : " + rawData, ex);
    			context.getExceptionData().add("Exception - updateStatus"+rawData+"^"+ex.fillInStackTrace());
    		    stats.incrementNumberOfErrorRecords();
            }		

            context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
			return success;
			
		} catch (Exception ex) {
			// no docs on exceptions yet - writing to a file
			logger.error("processDataRecord - Exception processing data record: " + rawData, ex);
			context.getProcessStatistics().incrementNumberOfErrorRecords();
			context.getExceptionData().add(createExceptionObject("processDataRecord - Exception processing data record^"+rawData+"^"+ex));
			// keep processing?
			//success = false;
		}
				
		return success;		
	}
    
	private void addReason(String formType, String reason) {
		if (formType.equals("H400H")) {
			stats.appendH400HReason(reason);
		} else if (formType.equals("H400B")) {
			stats.appendH400BReason(reason);
		} else {
			stats.appendH400FReason(reason);
		}
	}		
	
	// update stats last
	private void updateJobResultsLast(DataFileProcessExecutionContext context) {
		  stats.setProcessingEndDate(new Date());
		  updateJobResult(context);		
	}
	
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Validate.notNull(personService, "personService is required");
		Validate.notNull(handBookService, "hnadBookService is required");
	}
	
	/**
	 * @return Returns the personService.
	 */
	public PersonService getPersonService() {
		return personService;
	}

	/**
	 * @param personService
	 *            The personService to set.
	 */
	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}
	
	public HandBookService getHandBookService() {
		return handBookService;
	}

	public void setHandBookService(HandBookService handBookService) {
		this.handBookService = handBookService;
	}	
	
	public LookupService getLookupService() {
		return lookupService;
	}

	public void setLookupService(LookupService lookupService) {
		this.lookupService = lookupService;
	}
	public DemographicService getDemographicService() {
		return demographicService;
	}

	public void setDemographicService(DemographicService demographicService) {
		this.demographicService = demographicService;
	}	

	public CommsLogService getCommsLogService() {
		return commsLogService;
	}

	public void setCommsLogService(CommsLogService commsLogService) {
		this.commsLogService = commsLogService;
	}		

	public CommsTemplateDAO getTemplDAO() {
		return templDAO;
	}

	public void setTemplDAO(CommsTemplateDAO templDAO) {
		this.templDAO = templDAO;
	}	
	protected ProcessStatistics createProcessStatistics() {
        return new HandbookMailingResponseCode1RejectFileProcessStatistics ();
    }	
}	