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


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.springframework.core.io.FileSystemResource;

import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.ee.IRS1095B;
import gov.va.med.esr.common.model.ee.MECPeriod;
import gov.va.med.esr.common.model.party.SimpleAddress;
import gov.va.med.esr.common.model.person.id.PersonIdEntityKey;
import gov.va.med.esr.service.IRSTransmissionService;
import gov.va.med.esr.service.PersonMergeService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.esr.service.SystemParameterService;
import gov.va.med.fw.batchprocess.AbstractDataFileSingleRowIncrementProcess;
import gov.va.med.fw.batchprocess.DataFileProcessExecutionContext;
import gov.va.med.fw.batchprocess.DataProcessExecutionContext;
import gov.va.med.fw.batchprocess.FailedRecordWriterProcessCompletedHandler;
import gov.va.med.fw.util.FileUtils;
import gov.va.med.fw.util.StringUtils;

/**
 * WI#218485
 * reads file of Vet or CPE beneficiary data and brokers submit/request transmissions to the IRS
 * Input file is same format of ACA letter data file that goes to print vendor
 *
 * Created Sep 1, 2015
 * @author DNS   faulkj
 */
public class TransmitFileDataToIRSProcess extends
AbstractDataFileSingleRowIncrementProcess {

	static private IRSTransmissionService irsTransmissionService = null;
	private SystemParameterService systemParameterService = null;
	private final String SEP = "=";
	final private String EMPTY_STRING = "";
	private static String BATCH_TYPE = "B";
	private static String CORRECTION_IND = "O";
	private static String calendarYear;
	int maxBatchSize;
	CpeMecFileData dataRecord = null;
	private PersonMergeService personMergeService;
	private PersonService personService;
	static ArrayList<IRS1095B> batch = new ArrayList<IRS1095B>();

	public static class IRSFileProcessCompletedHandler extends FailedRecordWriterProcessCompletedHandler
	 {
		IRSFileProcessCompletedHandler() {super();}
		@Override
		public void dataProcessingComplete(DataProcessExecutionContext context) {

		 	//send the rest partial batch
			if (batch.size() > 0) {
				try {
					irsTransmissionService.sendSubmit(batch, BATCH_TYPE, CORRECTION_IND, calendarYear);
					batch.clear();
					context.getProcessStatistics().incrementNumberOfSuccessfulRecords();
				} catch (Exception e) {
	                if (logger.isErrorEnabled())
	                	logger.error("Unhandled Error during remainder CPE batch transfer to IRS for batch " + batch.toString(), e);
				}
			}

			super.dataProcessingComplete(context);
		}

	}



	@Override
    protected List doAcquireData(DataProcessExecutionContext context,
				FileSystemResource fileSystemResource) throws Exception {

			List xmlFile = new ArrayList();

			String args = (String)context.getExecutionArguments();
			if (!StringUtils.isEmpty(args)) {
				String rs = args;

				xmlFile.add(rs);

			} else {
				return super.doAcquireData(context, fileSystemResource);
			}

			return xmlFile;
		}

	public void processCustomDataFile(DataFileProcessExecutionContext context, List acquiredData) {

		FileInputStream fis = null;
		try {

			File xmlFile = new File((String)acquiredData.get(0));
			String correctionInd = "O";

			String args = (String)context.getExecutionArguments();
			if (!StringUtils.isEmpty(args)) {
				String[] params = args.split(",");
				if (params != null && params.length == 2) {
					xmlFile = new File(params[0]);
					correctionInd = params[1].trim();
				}
			}

			fis = new FileInputStream(xmlFile);
			byte[] data = IOUtils.toByteArray(fis);
			String content = new String(data);
			this.getIrsTransmissionService().submitCustomFile(content, correctionInd);

			context.getProcessStatistics().incrementNumberOfSuccessfulRecords();

		} catch (IOException e) {
			logger.error("Failed to read custom data file object" + e.getMessage());
			context.getProcessStatistics().incrementNumberOfErrorRecords();
		} finally {
			if (fis != null) {
				IOUtils.closeQuietly(fis);
			}
		}


	}

	@SuppressWarnings("unchecked")
	@Override
	public void processDataRecords(DataFileProcessExecutionContext context, List acquiredData) {

		//MEC_DataExtract_O_2015_V_2015123016452.txt
		//MEC_DataExtract_<correctionInd>_<tax_year>_<veteranInd>_timestamp.txt

		if (!StringUtils.isEmpty((String)context.getExecutionArguments())) {
			processCustomDataFile(context, acquiredData);
		} else {

		String[] types = context.getCurrentFile().getName().split("_");

		if (types != null && types.length == 6) {
			BATCH_TYPE = types[4];
			CORRECTION_IND = types[2];
			calendarYear = types[3];
		} else {
			logger.error("Invalid file name for MEC_DataExtract:" + context.getCurrentFile().getName());
			return;
		}

		try {
			maxBatchSize =  new Integer(this.getSystemParameterService().getByName("IRS Transmission Size").getValue()).intValue();
		} catch (Exception e) {
			if (logger.isErrorEnabled())
            	logger.error("Error during CPE batch transfer to IRS, cannot read system parameters", e);
		}


		for ( int i=0; i< acquiredData.size(); i++)
        {
			dataRecord = (CpeMecFileData) acquiredData.get(i);
			if (BATCH_TYPE.equalsIgnoreCase("V")) {
				//skip the record if deprecated id present
				try {
					String shortVpid = "";
					if (dataRecord.getVpid().length() == 30) {
						shortVpid = dataRecord.getVpid().substring(6, 23);
					}
					PersonIdEntityKey id = this.getPersonService().getPersonIdByVPID(CommonEntityKeyFactory.createVPIDEntityKey(shortVpid));
					if (id != null) {
						if (this.getPersonMergeService().hasDeprecatedRecord(id)) {
							logger.error("Ignoring deprecated record in IRS File data process for id:" + id.getKeyValueAsString());
							continue;
						}
					}
				} catch (Exception e) {
					logger.error("Exception during person retrieval" + e);
					continue;
				}
			}


			IRS1095B beneRecord = new IRS1095B();
        	try {

        		//get elements from input data record
        		beneRecord = buildLine(beneRecord, dataRecord);

        		batch.add(beneRecord);

        		//type not original, send one at a time
        		if (!CORRECTION_IND.equalsIgnoreCase("O")) {
        			this.getIrsTransmissionService().sendSubmit(batch, BATCH_TYPE, CORRECTION_IND, calendarYear);
        			batch.clear();
        		} else if (batch.size() == maxBatchSize) {
        			this.getIrsTransmissionService().sendSubmit(batch, BATCH_TYPE, CORRECTION_IND, calendarYear);
        			batch.clear();
        		}
    			context.getProcessStatistics().incrementNumberOfSuccessfulRecords();

            } catch (Exception e) {
                if (logger.isErrorEnabled())
                	logger.error("Error during CPE batch transfer to IRS for vpid " + dataRecord.getVpid(), e);

                context.getProcessStatistics().incrementNumberOfErrorRecords();

                context.getExceptionData().add(dataRecord + "^" + e.getMessage());
            }
            finally
            {
                // Check if we need to update the job result
                updateJobResult(context);

            }
        }

		}

		//write to the exception and failed file data at the end of the job.
		FailedRecordWriterProcessCompletedHandler dataFileCompletedHandler  = (FailedRecordWriterProcessCompletedHandler)getDataProcessCompletedHandler();
		dataFileCompletedHandler.writeExceptionData(context);
		dataFileCompletedHandler.writeFailedData(context);

	}

	/*
	 * Dummy implementation
	 * (non-Javadoc)
	 * @see gov.va.med.fw.batchprocess.AbstractDataFileSingleRowIncrementProcess#processDataRecord(gov.va.med.fw.batchprocess.DataFileProcessExecutionContext, java.lang.Object)
	 */
	protected  boolean processDataRecord(
            DataFileProcessExecutionContext context, Object bean){
		return false;
	}

	public IRSTransmissionService getIrsTransmissionService() {
		return irsTransmissionService;
	}

	public void setIrsTransmissionService(IRSTransmissionService irsTransmissionService) {
		this.irsTransmissionService = irsTransmissionService;
	}

	public SystemParameterService getSystemParameterService() {
		return systemParameterService;
	}

	public void setSystemParameterService(SystemParameterService systemParameterService) {
		this.systemParameterService = systemParameterService;
	}

	//this file data is actually for NPC vendor data transfer for the printed
	//form that gets mailed
	//requirement is to re-use same file and broker the 1095 data
	//to the IRS
	@SuppressWarnings("unchecked")
	private IRS1095B buildLine(IRS1095B beneRecord, CpeMecFileData dataRecord) {
		//aLine.append("A00=").append(name.getPrefix() == null ? EMPTY_STRING : name.getPrefix()).append(SEP)
		beneRecord.setNamePrefix(dataRecord.getNamePrefix().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getNamePrefix().split(SEP)[1]);
		beneRecord.setFirstName(dataRecord.getFirstName().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getFirstName().split(SEP)[1]);
		beneRecord.setMiddleName(dataRecord.getMiddleName().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getMiddleName().split(SEP)[1]);
		beneRecord.setLastName(dataRecord.getLastName().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getLastName().split(SEP)[1]);
		beneRecord.setNameSuffix(dataRecord.getNameSuffix().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getNameSuffix().split(SEP)[1]);
		beneRecord.setGender(dataRecord.getGender().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getGender().split(SEP)[1]);
		beneRecord.setIEN(dataRecord.getVpid().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getVpid().split(SEP)[1]);
		beneRecord.setSSN(dataRecord.getSsn().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getSsn().split(SEP)[1]);
		beneRecord.setDOB(dataRecord.getDateOfBirth().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getDateOfBirth().split(SEP)[1]);

		SimpleAddress beneAddress = new SimpleAddress();
		beneAddress.setLine1(dataRecord.getAddressLine1().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getAddressLine1().split(SEP)[1]);
		beneAddress.setLine2(dataRecord.getAddressLine2().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getAddressLine2().split(SEP)[1]);
		beneAddress.setLine3(dataRecord.getAddressLine3().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getAddressLine3().split(SEP)[1]);
		beneAddress.setCity(dataRecord.getCity().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getCity().split(SEP)[1]);
		beneAddress.setState(dataRecord.getState().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getState().split(SEP)[1]);
		beneAddress.setCountry(dataRecord.getCountryCode().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getCountryCode().split(SEP)[1]);
		beneAddress.setZipCode(dataRecord.getZipCode().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getZipCode().split(SEP)[1]);
		beneAddress.setPostalCode(dataRecord.getPostalCode().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getPostalCode().split(SEP)[1]);
		beneAddress.setCounty(dataRecord.getCounty().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getCounty().split(SEP)[1]);
		beneAddress.setProvince(dataRecord.getProvince().split(SEP).length < 2 ? EMPTY_STRING : dataRecord.getProvince().split(SEP)[1]);

		beneRecord.setAddress(beneAddress);

		MECPeriod benePeriod = new MECPeriod();
		benePeriod.setCoveredAll12Months((dataRecord.getCoveredAllYear().split(SEP).length == 2 && dataRecord.getCoveredAllYear().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
		HashMap coverageMap = new HashMap();

    	coverageMap.put("1", (dataRecord.getCoveredJan().split(SEP).length == 2 && dataRecord.getCoveredJan().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("2", (dataRecord.getCoveredFeb().split(SEP).length == 2 && dataRecord.getCoveredFeb().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("3", (dataRecord.getCoveredMar().split(SEP).length == 2 && dataRecord.getCoveredMar().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("4", (dataRecord.getCoveredApr().split(SEP).length == 2 && dataRecord.getCoveredApr().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("5", (dataRecord.getCoveredMay().split(SEP).length == 2 && dataRecord.getCoveredMay().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("6", (dataRecord.getCoveredJun().split(SEP).length == 2 && dataRecord.getCoveredJun().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("7", (dataRecord.getCoveredJul().split(SEP).length == 2 && dataRecord.getCoveredJul().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("8", (dataRecord.getCoveredAug().split(SEP).length == 2 && dataRecord.getCoveredAug().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("9", (dataRecord.getCoveredSep().split(SEP).length == 2 && dataRecord.getCoveredSep().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("10", (dataRecord.getCoveredOct().split(SEP).length == 2 && dataRecord.getCoveredOct().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("11", (dataRecord.getCoveredNov().split(SEP).length == 2 && dataRecord.getCoveredNov().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);
    	coverageMap.put("12", (dataRecord.getCoveredDec().split(SEP).length == 2 && dataRecord.getCoveredDec().split(SEP)[1].equalsIgnoreCase("Y")) ? true : false);

    	benePeriod.setCoverageMonths(coverageMap);
    	beneRecord.setMecPeriod(benePeriod);
    	return beneRecord;
	}

	public PersonMergeService getPersonMergeService() {
		return personMergeService;
	}

	public void setPersonMergeService(PersonMergeService personMergeService) {
		this.personMergeService = personMergeService;
	}

	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}


}
