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

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

import gov.va.med.esr.common.model.comms.CommsTemplate;
import gov.va.med.esr.common.model.comms.Correspondence;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType;
import gov.va.med.esr.common.model.lookup.CorrespondenceStatus;
import gov.va.med.esr.common.model.lookup.CorrespondenceType;
import gov.va.med.esr.common.model.lookup.ComLetterTemplateType.Code;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.persistent.comms.CommsTemplateDAO;
import gov.va.med.esr.common.persistent.comms.CorrespondenceDAO;
import gov.va.med.esr.common.persistent.history.CorrespondenceHistoryDAO;
import gov.va.med.esr.service.CorrespondenceService;
import gov.va.med.esr.service.DemographicService;
import gov.va.med.esr.service.LookupService;
import gov.va.med.esr.service.PersonService;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.service.ServiceException;


/**
 * common service to handle all transactions between the system and correspondence mailing and update services
 **/

public class CorrespondenceServiceImpl extends AbstractComponent implements CorrespondenceService {


	private static final long serialVersionUID = 8534346603323475694L;

	private LookupService lookupService = null;
	private PersonService personService = null;
	public static final String FIND_ADDRESS_H_BY_ID = "correspondenceQuery_findHistoryAddressById";
	public static final String PARAM_ADD_ID = "addressHId";
	private CorrespondenceDAO correspondenceDAO = null;
	private CommsTemplateDAO templDAO = null;
	private DemographicService demographicService;
	private CorrespondenceHistoryDAO correspondenceHistoryDAO = null;


	/**
	 * Inserts new CMS mail entry in pending mail queue for form number identified
	 *
     * @param correspondence, the person correspondence entry
     * @param formNumber, the letter template code to be mailed
     */
	public void triggerNewCMSCorrespondence(Correspondence correspondence, ComLetterTemplateType.Code formNumber) throws ServiceException {

		//don't set address or address_h_id during pending mail insert
		//set when generating and updating the status to Sent to CMS

		//populate mail queue only inserts the 1095 entry
		//during update from generation job, add the specific alive/dead letter entry as sent to CMS with the same address_h_id

		CommsTemplate templ = null;
		try {

			templ = (CommsTemplate) this.templDAO.findTemplateListByFormNumber(
					formNumber.getCode()).get(0);

			correspondence.setLetterTemplate(templ);

			correspondence.setCorrespondenceStatus((CorrespondenceStatus)this.getLookupService().getByCode(
	    			CorrespondenceStatus.class, CorrespondenceStatus.PENDING_TRANSMISSION_TO_CMS.getCode()));

			correspondence.setCorrespondenceType((CorrespondenceType)this.getLookupService().getByCode(
	    			CorrespondenceType.class, CorrespondenceType.CMS_MAILING.getCode()));

			correspondence.setStatusDate(new Date());

			this.getCorrespondenceDAO().saveObject(correspondence);

		} catch (DAOException ex) {
			logger.error("DAO Exception during triggerNewCorrespondence" , ex);
			throw new ServiceException(ex);
		}
	}

	/**
	 * Adds the appropriate letter type to accompany IRS 1095B mailing
	 * Letter is associated at time of mail generation of the tax form
	 *
     */
	public void associateACALetterType(Correspondence correspondence, ComLetterTemplateType.Code formNumber) throws ServiceException {

		CommsTemplate templ = null;
		try {

			templ = (CommsTemplate) this.templDAO.findTemplateListByFormNumber(
					formNumber.getCode()).get(0);

			correspondence.setLetterTemplate(templ);

			correspondence.setCorrespondenceStatus((CorrespondenceStatus)this.getLookupService().getByCode(
	    			CorrespondenceStatus.class, CorrespondenceStatus.SENT_TO_CMS.getCode()));

			correspondence.setCorrespondenceType((CorrespondenceType)this.getLookupService().getByCode(
	    			CorrespondenceType.class, CorrespondenceType.CMS_MAILING.getCode()));

			correspondence.setStatusDate(new Date());

			this.getCorrespondenceDAO().saveObject(correspondence);

		} catch (DAOException ex) {
			logger.error("DAO Exception during triggerNewCorrespondence" , ex);
			throw new ServiceException(ex);
		}
	}

	/**
	 * Updates the correspondence entry to status indicated
	 * and error message if necessary
	 *
     */
	public void updateACACorrespondence(Correspondence correspondence, CorrespondenceStatus.Code status, String errMsg) throws ServiceException {

		try {
			//if updating to Sent, need to set address id's at time of generation
			if (status != null && status.equals(CorrespondenceStatus.SENT_TO_CMS)) {
				if (correspondence.getMailingAddress() != null) {

					this.getDemographicService().saveAddress(correspondence.getMailingAddress());

					//get address_h to track address at time of mailing
					correspondence.setAddressId(this.getCorrespondenceDAO().findAddressHistoryIdByPersonId(correspondence.getPersonId()));
				}
			}

			if (status != null) {

				correspondence.setCorrespondenceStatus((CorrespondenceStatus)this.getLookupService().getByCode(
		    			CorrespondenceStatus.class, status.getCode()));
			}

			correspondence.setStatusDate(new Date());
			correspondence.setErrorDescription(errMsg);

			this.getCorrespondenceDAO().saveObject(correspondence);

		} catch (DAOException ex) {
			logger.error("DAO Exception during Update ACA Correspondence" , ex);
			throw new ServiceException(ex);
		}
	}

	/**
	 * Utility method to lookup the correspondence letter form
	 *
     */
	public CommsTemplate getTemplateByForm(Code formNumber) throws ServiceException {
		try {
			return (CommsTemplate) this.templDAO.findTemplateListByFormNumber(
					formNumber.getCode()).get(0);
		} catch (DAOException e) {
			logger.error("DAO Exception during getTemplateByForm" , e);
			throw new ServiceException(e);
		}
	}

	/**
	 * Finds all records for specified person that are pending mail correspondence to CMS for specified formNumber
	 *
     */
	public ArrayList<Correspondence> getPendingPersonCorrespondence(BigDecimal personId, Code formNumber) throws ServiceException {

		try {
			ArrayList<Correspondence> results = this.getCorrespondenceDAO().findPendingCorrespondenceByForm
					(personId, formNumber.getCode());

			if (results != null && results.size() > 0) {
				return results;
			}

		} catch (DAOException ex){
			logger.error("DAO Exception during getPendingPersonCorrespondence" , ex);
			throw new ServiceException(ex);
		}

		return null;
	}

	/**
	 * Finds all records for specified person that are sent to CMS for that form number
	 *
     */
	public ArrayList<Correspondence> getSentPersonCorrespondence(BigDecimal personId, Code formNumber) throws ServiceException {

		try {
			ArrayList<Correspondence> results = this.getCorrespondenceDAO().findSentCorrespondenceByForm
					(personId, formNumber.getCode());

			if (results != null && results.size() > 0) {
				return results;
			}

		} catch (DAOException ex){
			logger.error("DAO Exception during getSentPersonCorrespondence" , ex);
			throw new ServiceException(ex);
		}

		return null;
	}


	//if presumed deceased, or whatever other rules to not send mail for a verified record
	public boolean shouldSuppressMailCorrespondence(Person person) throws ServiceException {
		boolean shouldSuppress = false;
		if (person.getMailStopReason() != null && !person.getMailStopReason().isEmpty()) {
			shouldSuppress = true;
		}
		return shouldSuppress;
	}


	/**
	 * Cancel pending mail
	 * Triggered by UI before the records is sent to CMS
	 *
     */
	public void cancelCorrespondence(BigDecimal correspondenceId) throws ServiceException {
		try {
			Correspondence corr = this.getCorrespondenceDAO().findById(correspondenceId);
			this.updateACACorrespondence(corr, CorrespondenceStatus.CANCEL_BY_HEC, "Pending Mail Correspondence Cancelled by ES User");

		} catch (DAOException e) {
			logger.error("DAO Exception during cancelCorrespondence" , e);
		}
	}


	/**
	 * Retrieves correspondence detail record including historical address and historical mail status
	 * For display on UI detail
	 *
     */
	@SuppressWarnings("unchecked")
	public Correspondence getCorrespondenceWithHistory(BigDecimal correspondenceId) throws ServiceException {
		try {
			Correspondence corr = this.getCorrespondenceDAO().findById(correspondenceId);

	        if (corr.getAddressId() != null) {
	        	Address mailedAddress = null;
	        	try {
	        		mailedAddress = this.getCorrespondenceDAO().getHistoricalAddress(corr.getAddressId());
	        	} catch (Exception ex) {
	        		logger.error("DAO Exception during getyCorrespondence" , ex);
	        	}
	        	corr.setMailingAdress(mailedAddress);
	        }

	        ArrayList<Correspondence> corrHistory = new ArrayList<Correspondence>(this.getCorrespondenceHistoryDAO().getCorrespondenceHistory(correspondenceId));

	        corr.setStatusHistory(corrHistory);

			return corr;

		} catch (DAOException e) {
			logger.error("DAO Exception during getCorrespondence" , e);
			return null;
		}
	}


	/**
	 * Remail utility to put previous form back in pending mail queue
	 *
     */
	public void remailCorrespondence(BigDecimal correspondenceId) throws ServiceException {
		try {
			Correspondence orig = this.getCorrespondenceDAO().findById(correspondenceId);
			Correspondence remail = new Correspondence();
			remail.setEffectiveDate(orig.getEffectiveDate());
			remail.setPersonId(orig.getPersonId());

			this.triggerNewCMSCorrespondence(remail, ComLetterTemplateType.Code.getByCode(orig.getLetterTemplate().getCommsTemplateFormNumber()));


		} catch (DAOException e) {
			logger.error("DAO Exception during remailCorrespondence" , e);
		}

	}


	/**
	 * Gets all correspondence for person, in all status, for specified list of form numbers
	 *
     */
	public ArrayList<Correspondence> getPersonCorrespondence(BigDecimal personId, ArrayList<Code> formNumbers) throws ServiceException {
		try {

			ArrayList<Correspondence> allResults =  new ArrayList<Correspondence>();

			for (int i = 0; i < formNumbers.size(); i++) {

				ArrayList<Correspondence> results = this.getCorrespondenceDAO().findAllCorrespondenceByForm
						(personId, formNumbers.get(i).getCode());

				if (results != null && results.size() > 0) {
					allResults.addAll(results);
				}
			}

			return allResults;

		} catch (Exception ex){
			logger.error("DAO Exception during getPendingPersonCorrespondence" , ex);
			return null;
		}

	}

	public CorrespondenceDAO getCorrespondenceDAO() {
		return correspondenceDAO;
	}


	public void setCorrespondenceDAO(CorrespondenceDAO correspondenceDAO) {
		this.correspondenceDAO = correspondenceDAO;
	}


	public LookupService getLookupService() {
		return lookupService;
	}


	public void setLookupService(LookupService lookupService) {
		this.lookupService = lookupService;
	}

	public PersonService getPersonService() {
		return personService;
	}

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


	public CommsTemplateDAO getTemplDAO() {
		return templDAO;
	}


	public void setTemplDAO(CommsTemplateDAO templDAO) {
		this.templDAO = templDAO;
	}


	public DemographicService getDemographicService() {
		return demographicService;
	}


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


	public CorrespondenceHistoryDAO getCorrespondenceHistoryDAO() {
		return correspondenceHistoryDAO;
	}

	public void setCorrespondenceHistoryDAO(
			CorrespondenceHistoryDAO correspondenceHistoryDAO) {
		this.correspondenceHistoryDAO = correspondenceHistoryDAO;
	}


}
