package gov.va.med.esr.service;

// Java classes
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Set;

// Framework Classes
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.persistent.DAOException;
import gov.va.med.fw.service.ServiceException;

// ESR Classes
import gov.va.med.esr.common.clock.Clock;
import gov.va.med.esr.common.model.ee.EnrollmentDetermination;
import gov.va.med.esr.common.model.lookup.EnrollmentPriorityGroup;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.id.PersonEntityKey;
import gov.va.med.esr.service.external.person.EligibilitySummary;
import gov.va.med.esr.service.impl.ChangeEvent;
import gov.va.med.esr.service.impl.HistoricalInfo;

/**
 * The Eligibility and Enrollment Service.
 * Project: Common
 *
 * @author DNS   LEV
 * @author Andrew Pach
 * @version 3.0
 */
public interface EligibilityEnrollmentService extends Serializable
{
    /**
     * Assesses the E&E Impact on the incoming person. This method is used when igetEligibilityEnrollmentServicenvoked directly from the GUI.  It does
     * not result in the triggering of letters.
     *
     * @param incoming The incoming person
     *
     * @return The updated person
     * @throws ServiceException if any problems were encountered.
     */
    public Person assessEEImpact(Person incoming) throws ServiceException;

    /**
     * Assesses the E&E Impact on the incoming person. This method should be invoked from UI oriented business services
     * (e.g. update methods).  The caller can control whether or not to produce letter triggers. If isReviewOnly is true,
     * this method will NOT trigger letters.  This method is the same as calling assessEEImpact(incoming, true,
     * isReviewOnly, null).
     *
     * @param incoming The incoming person
     * @param isReviewOnly Flag to determine whether this assessment is being done as a review only assessment.
     *
     * @return The updated person
     * @throws ServiceException if any problems were encountered.
     */
    public Person assessEEImpact(Person incoming, boolean isReviewOnly) throws ServiceException;

    /**
     * Assesses the E&E Impact on the incoming person. This method should be invoked from UI oriented business services
     * (e.g. update methods).  The caller can control whether or not to produce letter triggers. If isReviewOnly is true,
     * this method will NOT trigger letters.  This method supports the passing of an optional clock type.
     *
     * @param incoming The incoming person
     * @param isReviewOnly Flag to determine whether this assessment is being done as a review only assessment.
     * @param clockType the clock type to use during the assessment.
     *
     * @return The updated person
     * @throws ServiceException if any problems were encountered.
     */
    public Person assessEEImpact(Person incoming, boolean isReviewOnly, Clock.Type clockType) throws ServiceException;

    public Person assessEEImpact(Person incoming, boolean isDataFromGUI, boolean isReviewOnly) throws ServiceException;

    public Person assessEEImpact(Person incoming, boolean isDataFromGUI, boolean isReviewOnly, boolean shouldTriggerHBP) throws ServiceException;
 
    /**
     * Assesses the E&E Impact on the incoming person. This method can be invoked from the UI or Messaging, but requires
     * the setting of the appropriate flags (i.e. isDataFromUI and isReviewOnly).
     *
     * @param incoming The incoming person
     * @param isDataFromGUI Flag to determine whether this call is being made from a UI flow.
     * @param isReviewOnly Flag to determine whether this assessment is being done as a review only assessment.
     * @param sendingFacility the sending facility of the message so that isMessageFromVOA can be calculated	
     * @return The updated person
     * @throws ServiceException if any problems were encountered.
     */
    public Person assessEEImpact(Person incoming, boolean isDataFromGUI, boolean isReviewOnly, VAFacility sendingFacility) throws ServiceException;

    /**
     * Process expired means test. If the Person is not subject to MT return false otherwise true
     *
     * @param key
     *
     * @return
     * @throws ServiceException
     */
    public boolean processExpiredMeansTestForBatchProcess(PersonEntityKey key) throws ServiceException;

    /**
     * Assess impact of applying eligibility rules. Retrieves the person from a database using the key then apply rules.
     * Can control whether or not to persist the resulting person. If triggerEvents is true, rule events will be
     * triggered.
     *
     * @param key
     * @param savePerson
     * @param triggerEvents
     *
     * @return Person - result Person
     * @throws ServiceException
     */
    public Person processCalculateEE(PersonEntityKey key, boolean savePerson, boolean triggerEvents)
        throws ServiceException;
    
    public Person processCalculateEEForCleanup(PersonEntityKey key, boolean savePerson, boolean triggerEvents)
    throws ServiceException;    
    
    /**
     * Assess impact of applying eligibility rules once the override flag is set. Retrieves the person from a database using 
     * the key then apply rules. Can control whether or not to persist the resulting person. If triggerEvents is true, rule 
     * events will be triggered.
     *
     * @param key
     * @param savePerson
     * @param triggerEvents
     *
     * @return Person - result Person
     * @throws ServiceException
     */
    public Person processCalculateEEOverride(PersonEntityKey key, boolean savePerson, boolean triggerEvents)
        throws ServiceException;

    /**
     * Update the person's enrollment data. Trigger appropriate letter, messages, and bulletins
     *
     * @param incoming
     *
     * @return
     * @throws ServiceException
     */
    public Person updateEnrollmentData(Person incoming) throws ServiceException;

    /**
     * Update the person's eligibility data. Trigger appropriate letter, messages, and bulletins
     *
     * @param incoming
     *
     * @return
     * @throws ServiceException
     */
    public Person updateEligibilityData(Person incoming) throws ServiceException;

    /**
     * Checks if the period of service is needed.
     *
     * @param incoming
     *
     * @return True if a service period is needed or false if not.
     */
    public boolean isServicePeriodNeeded(Person incoming) throws ServiceException;

    /**
     * Returns a list of history change times for the Eligibility History screen.  Returns a set of ChangeEvents.
     *
     * @param personID
     *
     * @return the change times
     */
    public Set getEligibilityHistoryChangeTimes(EntityKey personID) throws ServiceException;

    /**
     * For a given ChangeEvent, returns the eligibility history data corresponding to the Eligibility History screen.
     * Please do not use this method for backend processing purposes due to performance costs.
     *
     * @param event
     *
     * @return the history information
     */
    public HistoricalInfo getEligibilityHistoryByChangeTime(ChangeEvent event) throws ServiceException;

    /**
     * Returns a list of history change times for the Enrollment History screen.  Returns a set of ChangeEvents.
     *
     * @param personID
     *
     * @return Set<ChangeEvent>
     * @throws ServiceException
     */
    public Set getEnrollmentHistoryChangeTimes(EntityKey personID) throws ServiceException;

    /**
     * For a given ChangeEvent, returns the Enrollment history data corresponding to the Enrollment History screen.
     * Please do not use this method for backend processing purposes due to performance costs.
     *
     * @param event
     *
     * @return
     * @throws ServiceException
     */
    public HistoricalInfo getEnrollmentHistoryByChangeTime(ChangeEvent event) throws ServiceException;

    /**
     * For ee calculation: returns the application date corresponding to the earliest unverified enrollment
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public Date getAppDateFromEarliestUnverifiedEnrollment(EntityKey personId) throws ServiceException;

    /**
     * Returns the enrollment priority code and status code before PH was added. Used when letter 630D is triggered
     * @param personId
     * @return String[] with enrollment priority code and enrollment status code. Return null if not found.
     */
    public String[] getEnrollmentPriorityBeforePH(EntityKey personId) throws ServiceException ;

    /**
     * For ee calculation: returns the effective date for the earliest enrollment with not null effective date.
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public Date getFirstNotNullEffDate(EntityKey personId) throws ServiceException;

    /**
     * Returns enrollment data for the immediately prior enrollment.  Only EnrollmentDetermination data is populated for
     * person.
     *
     * @param personId
     *
     * @return the updated person
     */
    public Person getPersonForPriorEnrollment(EntityKey personId) throws ServiceException;

    /**
     * Returns the enrollment status and application date for the earliest enrollment.
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public Object[] getStatusAndAppDateForEarliest(EntityKey personId) throws ServiceException;

    /**
     * Returns the codes for priority group and priority subGroup for the most recent enrollment.
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public String[] getPriorityGrpsForMostRecent(EntityKey personId) throws ServiceException;

    /**
     * Returns the Enrollment Date from the earliest enrollment with Verified Status UNLESS a Cancel Decline Status is
     * encountered, in which case use subsequent (one more recent than cancel).
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public Date getEnrollmentDateForEarliestVerifiedUnlessCancelled(EntityKey personId) throws ServiceException;
    
    public Date getEffectiveDateForEarliestVerifiedUnlessCancelledOrRejectedBelowEnrollmentThreshold(EntityKey personId) throws ServiceException;
    
    /**
     * 
     * @param personId
     * @return
     * @throws ServiceException
     */
    public EnrollmentDetermination getEnrollmentDeterminationForEarliestVerifiedUnlessCancelledOrRejectedBelowEnrollmentGroupThreshold(EntityKey personId) throws ServiceException;

    /**
     * Returns true if there is ANY application date that is prior to EGT Setting effective date
     */
    public boolean isApplicationDatePriortoEGTEffectiveDate(EntityKey personId)
        throws ServiceException;

    /**
     * Return true if the person has ANY enrollment record before the specified date
     * @param personId
     * @param beofreDate
     * @return
     * @throws DAOException
     */
    public boolean hasAnyEnrollmentRecordBeforeDate(EntityKey personId, Date beforeDate) throws ServiceException;
    
    
    /**
     * Returns true if Verified Enrollment exists in the Past with the given Eligibility Type Code
     *
     * @param personId
     * @param eligiblityTypeCode
     *
     * @return
     * @throws ServiceException
     */
    public boolean isVerifiedEnrollmentExistsForEligibilityCode(EntityKey personId,
        String eligiblityTypeCode) throws ServiceException;
    
    /**
     * Returns true if Verified Enrollment exists in the Past with the given Medicaid Eligibility
     * DNS   doank: CCR 8797, Use different method for Migrated Record because Elibility Factor is not set in these
     * This can be generalized with different Query for different specific situation.
     * 
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public boolean isVerifiedEnrollmentExistsForMedicaidEligibility(EntityKey personId) throws ServiceException;

    /**
     * Returns earliest verified enrollment effective date with eligibility code AG and AOE location DMZ
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public Date getEarliestEnrollmentEffectiveDatewithAOWatDMZ(EntityKey personId)
        throws ServiceException;

    /**
     * Returns true if verified enrollment exists with Service Connection Award Percent >= given Value
     *
     * @param personId
     * @param percent
     *
     * @return
     * @throws ServiceException
     */
    public boolean isVerifiedEnrollmentExistsforSvcConnPercent(EntityKey personId,
        Integer percent) throws ServiceException;

    /**
     * Returns the income year for a MT that is linked to a verified enrollment
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    /**
     * @deprecated Fix for CR_8675 modified to return multiple incomeYears in the below method.
     */
    public Integer getIncomeYearForVerifiedMT(EntityKey personId) throws ServiceException;

    public List getIncomeYearsForVerifiedMT(EntityKey personId) throws ServiceException;
    
    // CodeCR10023 and CR9803 and CCR ESR_REEG_00010057
    public List getIncomeYearsFromVerifiedEnrollmentDueToP8(EntityKey personId) throws ServiceException;
    
   
    /**
     * CodeCR10023 and CR9803
     * Get the most recent verified Enrollment Priority Group and Sub Group
     * 
     * @param personId
     * @return Priority Group and Priority Sub Group
     */
    public String[] getMostRecentVerifiedEnrollmentPriorityGroups(EntityKey personId) throws ServiceException;    
    
    /**
     * CodeCR10023 and CR9803
     * 
     * @param personId
     * @param relaxPercent
     * @return
     * @throws ServiceException
     */
    public boolean hasIncomeTestMeetingP8RecheckCriteria(EntityKey personId, float relaxPercent) throws ServiceException;    

    /**
     * CodeCR10023 and CR9803
     * 
     * @param personId
     * @return
     * @throws ServiceException
     */
    public List getHistoricalIncomeYearsForVerifiedMT(EntityKey personId) throws ServiceException;    
    
    
    /**
     * Returns true if verified enrollment exists for Combat Veteran eligibility code
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public boolean isVerifiedEnrollmentExistsforCombatVeteran(EntityKey personId)
        throws ServiceException;

    /**
     * Return most recent enrollment data for continuous enrollment (Excludind the status
     * "'6','15','16','17','18','19','20','21','23'"
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public EnrollmentDetermination getMostRecentEnrollmentforContinuousEnrollment(EntityKey personId)
        throws ServiceException;

    /**
     * Returns true if a verified enrollment exists, false otherwise
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public boolean isVerifiedEnrollmentExists(EntityKey personId) throws ServiceException;

    /**
     * Returns the enrollment priority group code for most recent enrollment where code is not null.
     *
     * @param personId
     *
     * @return
     * @throws ServiceException
     */
    public String getMostRecentNonNullPriorityCode(EntityKey personId) throws ServiceException;

    public String getMostRecentNonNullPriorityLevelByDate(EntityKey personId, Date beforeDate) throws ServiceException;

    /**
     * Remove all eligibilities from a non-veteran
     *
     * @param incoming
     *
     * @throws ServiceException
     */
    public void removeAllEligibilityFactorsFromNonVet(Person incoming) throws ServiceException;

    /**
     * Remove  all eligibilities from a person
     *
     * @param incoming
     *
     * @throws ServiceException
     */
    public void removeAllEligibilityFactors(Person incoming) throws ServiceException;

    /**
     * HealtheVet api that exposes EE data to the enterprise.  Data set exposed is largely driven by client
     * requirements.
     *
     * @param vpid
     * @return
     * @throws ServiceException
     */
    public EligibilitySummary getEligibilitySummary(gov.va.med.esr.service.external.person.VPIDEntityKey vpid) throws ServiceException;

    /**
     * Get POW change history times
     * @param personID
     * @return
     * @throws ServiceException
     */
    public Set getPOWHistoryChangeTimes(EntityKey personID) throws ServiceException;

    /**
     * Get POW POW Historical view at specified event time
     * @param event
     * @return
     * @throws ServiceException
     */
    public HistoricalInfo getPOWHistoryByChangeTime(ChangeEvent event) throws ServiceException;

    /**
     * Retrieve person enrollment history records 
     * @param personId
     * @throws ServiceException
     */
    public List getEnrollmentDeterminationHistory(EntityKey personId) throws ServiceException;
    
    public boolean getPriorToEnrDetermHistory(EntityKey personId, Date beforeDate, Date recModifiedDate) throws ServiceException;

}