package com.agilex.vamf.missionhealth.datalayer;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.agilex.vamf.missionhealth.domain.comparator.ServiceAgeComparator;
import com.agilex.vamf.missionhealth.domain.enumeration.StandingType;
import com.agilex.vamf.missionhealth.message.EmailNotificationPublisher;
import com.agilex.vamf.missionhealth.service.*;
import com.agilex.vamf.utils.DateHelper;
import com.agilex.vamf.utils.PropertyHelper;
import com.agilex.vamf.missionhealth.domain.*;

import org.springframework.stereotype.Service;

import com.agilex.healthcare.mobilehealthplatform.security.MhpUserFactory;
import com.agilex.vamf.missionhealth.domain.enumeration.MissionStatus;

@Service
public class MissionHealthDataService {
    private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory.getLog(MissionHealthDataService.class);

    private static final int CRITICAL_MISSION_INTERVAL = 50;
    private static final int MISSION_READINESS_RANK_CHECK=3;
    
    private static final String REMINDER_TYPE_DAILY="Daily";
    private static final String REMINDER_TYPE_MID_WEEK="Mid-Mission";
    private static final String REMINDER_TYPE_END_WEEK="End of Mission";
    
    private static final Integer LOSING_TROOPS_FOR_POINTS=50;
    private static final Integer LOSING_TROOPS_FOR_RANK=8;
    private static final Integer LOSING_TROOPS_FOR_FAILEDMISSION=3;
    private static final Integer MIN_TROOPS=1;
	
    @Resource
    MissionHealthDataLayer missionHealthDataLayer;

    @Resource
    PointService pointService;

    @Resource
    EmailNotificationPublisher publisher;
    
    @Resource
    private PropertyHelper propertyHelper;
    
	public MissionHealthProfile saveMissionHealthProfile(MissionHealthProfile missionHealthProfile) {
		logger.debug(String.format("saveMissionHealthProfile missionHealthProfile: '%1s'", missionHealthProfile));

		MissionHealthDetail missionHealthDetail = missionHealthDataLayer.getMissionHealthDetail(missionHealthProfile.getPatientIdentifier().getUniqueId());

        if (missionHealthDetail.getMissionHealthProfile() == null && MhpUserFactory.createFromSecurityContext()!= null) {
			com.agilex.healthcare.mobilehealthplatform.domain.Patient authPatient = MhpUserFactory.createFromSecurityContext().getPatient();
			missionHealthProfile.setGender(authPatient.getGender());
			missionHealthProfile.setDateOfBirth(authPatient.getDateOfBirth().getDate());
			missionHealthDetail.setMissionHealthProfile(missionHealthProfile);
		}
		missionHealthDetail.setMissionHealthProfile(missionHealthProfile);
        missionHealthDetail.setRank(missionHealthDataLayer.getMissionHealthRank(missionHealthProfile.getService(), missionHealthDetail.getRank().getLevel()));
		pointService.updatePointsForLogging(missionHealthDetail);
		if (missionHealthDetail.getMissionHealthProfile() != null 
				&& (missionHealthDetail.getMissionHealthProfile().getReminder() != null && !(missionHealthDetail.getMissionHealthProfile().getReminder().isEmpty())) 
        		&& (missionHealthDetail.getMissionHealthProfile().getService() != null && !(missionHealthDetail.getMissionHealthProfile().getService().isEmpty())) 
				&& !(missionHealthDetail.getMissionProfilePoints() > 0)) {
			pointService.updatePointsForCompletingMissionProfile(missionHealthDetail);
		}
        missionHealthDetail = missionHealthDataLayer.updateMissionHealthDetail(missionHealthDetail);
        return missionHealthDetail.getMissionHealthProfile();
		
	}

	public MissionHealthDetail updateMissionHealthProfile(MissionHealthProfile missionHealthProfile) {
		logger.debug(String.format("updateMissionHealthProfile missionHealthProfile: '%1s'", missionHealthProfile));

		MissionHealthDetail missionHealthDetail = missionHealthDataLayer.getMissionHealthDetail(missionHealthProfile.getPatientIdentifier().getUniqueId());
		missionHealthDetail.setMissionHealthProfile(missionHealthProfile);
        MissionHealthRank missionHealthRank = missionHealthDataLayer.getMissionHealthRank(missionHealthProfile.getService(), missionHealthDetail.getRank().getLevel());
        missionHealthDetail.setRank(missionHealthRank);
        if (missionHealthDetail.getMissionHealthProfile() != null
        		&& (missionHealthDetail.getMissionHealthProfile().getReminder() != null && !(missionHealthDetail.getMissionHealthProfile().getReminder().isEmpty())) 
        		&& (missionHealthDetail.getMissionHealthProfile().getService() != null && !(missionHealthDetail.getMissionHealthProfile().getService().isEmpty())) 
        		&& !(missionHealthDetail.getMissionProfilePoints() > 0)
        		) {
			pointService.updatePointsForCompletingMissionProfile(missionHealthDetail);
		}
        missionHealthDetail = missionHealthDataLayer.updateMissionHealthDetail(missionHealthDetail);
		
		return missionHealthDetail;
	}

    public MissionHealthDetail getMissionHealthDetail(PatientIdentifier patientIdentifier, Date sessionStart) {
        MissionHealthDetail missionHealthDetail = getMissionHealthDetail(patientIdentifier);
        if(null==missionHealthDetail.getLastSessionStart() || missionHealthDetail.getLastSessionStart().before(sessionStart)){
            missionHealthDetail.setTotalLoginsForCycle(missionHealthDetail.getTotalLoginsForCycle()+1);
            missionHealthDetail.setLastSessionStart(sessionStart);
            missionHealthDetail = missionHealthDataLayer.updateMissionHealthDetail(missionHealthDetail);
        }
        return missionHealthDetail;
    }
	
	public MissionHealthDetail getMissionHealthDetail(PatientIdentifier patientIdentifier) {
		logger.debug(String.format("getMissionHealthDetail patientIdentifier: '%1s'", patientIdentifier));
        MissionHealthDetail missionHealthDetail = missionHealthDataLayer.getMissionHealthDetail(patientIdentifier.getUniqueId());
        if (missionHealthDetail == null) {
			missionHealthDetail = new MissionHealthDetail();
			missionHealthDetail.setPatientId(patientIdentifier.getUniqueId());
            missionHealthDetail.setRank(new MissionHealthRank());
            missionHealthDetail.setRankEffectiveDate(new Date());
		}
		if (pointService.updatePointsForLogging(missionHealthDetail)) {
			if (missionHealthDetail.getId() == null) {
				missionHealthDetail=missionHealthDataLayer.saveMissionHealthDetail(missionHealthDetail);
			} else {
				missionHealthDetail=missionHealthDataLayer.updateMissionHealthDetail(missionHealthDetail);
			}
		}
        return missionHealthDetail;
	}
	
	public MissionHealthDetail updateMissionHealthDetail(MissionHealthDetail missionHealthDetail) {
		logger.debug(String.format("updateMissionHealthDetail missionHealthDetail: '%1s'", missionHealthDetail));

	    pointService.updatePointsForLogging(missionHealthDetail);
        return missionHealthDataLayer.updateMissionHealthDetail(missionHealthDetail);
	}

	public void removeMissionHealthDetail(MissionHealthDetail missionHealthDetail) {
		logger.debug(String.format("removeMissionHealthDetail missionHealthDetail: '%1s'", missionHealthDetail));

		missionHealthDataLayer.removeMissionHealthDetail(missionHealthDetail);
		
	}
	
	public MissionHealthPartialDetail updateSmartInfoPoints(PatientIdentifier patientIdentifier) {
		logger.debug(String.format("updateSmartInfoPoints patientIdentifier: '%1s'", patientIdentifier));
		MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
		PointService pointService = new PointService();
        MissionHealthPartialDetail mhdSubset=new MissionHealthPartialDetail();
		if (mhd!=null){
            if(pointService.updatePointsForSmartInfo(mhd)) {
                mhd = missionHealthDataLayer.updateMissionHealthDetail(mhd);
            }
            mhdSubset.setPatientIdentifier(mhd.getPatientIdentifier());
            mhdSubset.setPoints(mhd.getPoints());
            mhdSubset.setStanding(mhd.getStanding());
        }
		return mhdSubset;
	}
	
	public MissionHealthPartialDetail updateEmailFacebookPoints(PatientIdentifier patientIdentifier) {
		logger.debug(String.format("updateEmailFacebookPoints patientIdentifier: '%1s'", patientIdentifier));
		MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
		MissionHealthPartialDetail mhdSubset=new MissionHealthPartialDetail();
		PointService pointService = new PointService();
		if (mhd!=null) {
            if(pointService.updatePointsForEmailOrFacebook(mhd)) {
                mhd = missionHealthDataLayer.updateMissionHealthDetail(mhd);
            }
            mhdSubset.setPatientIdentifier(mhd.getPatientIdentifier());
            mhdSubset.setPoints(mhd.getPoints());
            mhdSubset.setStanding(mhd.getStanding());
		}
		return mhdSubset;
    }

    public Mission createNewMission(PatientIdentifier patientIdentifier, Mission newMission){
        Mission mission = newMission;
        MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
        PointService pointService = new PointService();
        if(null!=mhd){
            PointsRule ruleForLevel = missionHealthDataLayer.getPointsRuleForLevel(mhd.getRank().getLevel());
            if(null!=ruleForLevel){
                Integer missionsAllUsers = missionHealthDataLayer.getTotalMissionsAcrossAllUsers();
                mission = pointService.setPointsForNewMission(ruleForLevel, mission, ((missionsAllUsers+1)%CRITICAL_MISSION_INTERVAL==0));
                mission.setId(mhd.getId() + "-" + mhd.getTotalMissions());
                mission.setStartDate(DateHelper.beginOfDate(new Date()));
                mission.setHomeService(mhd.getMissionHealthProfile().getService());
                if(null==mission.getStatus())
                    mission.setStatus(MissionStatus.ACTIVE);
                mhd.addMission(mission);
                missionHealthDataLayer.updateMissionHealthDetail(mhd);
            }
        }
        return mission;
    }

    public Mission updateMission(PatientIdentifier patientIdentifier, Mission mission){
        MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
        if(null!=mission.getId()){
            int missionIndex = mhd.getCurrentMissions().indexOf(mission);
            if(missionIndex>=0){
                mhd.getCurrentMissions().set(missionIndex, mission);
                missionHealthDataLayer.updateMissionHealthDetail(mhd);
                return mission;
            } else {
                missionIndex = mhd.getMissions().indexOf(mission);
                if (missionIndex>=0){
                    mhd.getMissions().set(missionIndex, mission);
                    missionHealthDataLayer.updateMissionHealthDetail(mhd);
                }
            }
        }
        return null;
    }
    
    public MissionHealthDetail insertMissionReadinessReport(PatientIdentifier patientIdentifier, MissionReadinessReport missionReadinessReport){
        MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
        PointService pointService = new PointService();
        MissionHealthDetail partialMhd= null; 
        if(mhd!=null && missionReadinessReport!=null){
        	missionReadinessReport.setInsDate(new Date());
        	mhd.addMissionReadinessReport(missionReadinessReport);
	        if(mhd.getRank().getLevel()!=0 && mhd.getPendingRank()!=null){
	        	mhd.setPreviousRank(mhd.getRank());
	        	mhd.setRank(mhd.getPendingRank());
	        	mhd.setPendingRank(null);
	        	mhd.setRankEffectiveDate(new Date());
	        	mhd.setPromoted(true);
	        	pointService.updatePointsForMissionReadinessReport(mhd);
	        }
	        if((mhd.getRank().getLevel()==0 && mhd.getMissionReadinessReports().size()==1) || (mhd.getRank().getLevel()>0 && mhd.getRank().getLevel()%MISSION_READINESS_RANK_CHECK==0)){
	        	mhd=missionHealthDataLayer.updateMissionHealthDetail(mhd);
	        	partialMhd=new MissionHealthDetail();
	        	partialMhd.addMissionReadinessReport(mhd.getMissionReadinessReports().get(mhd.getMissionReadinessReports().size()-1));
			    partialMhd.setRank(mhd.getRank());
			    partialMhd.setRankEffectiveDate(mhd.getRankEffectiveDate());
			    partialMhd.setPoints(mhd.getPoints());
			    partialMhd.setPromoted(mhd.isPromoted());
			    partialMhd.setPreviousRank(mhd.getPreviousRank());
			    partialMhd.setPendingRank(mhd.getPendingRank());
	        }
        }
        return partialMhd;
    }
    
    public MissionHealthPartialDetail savePromotedStatus(PatientIdentifier patientIdentifier){
    	MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
        mhd.setPromoted(false);
        mhd=missionHealthDataLayer.updateMissionHealthDetail(mhd);
        MissionHealthPartialDetail partialMhd=null;
        if(!mhd.isPromoted()){
        	partialMhd=new MissionHealthPartialDetail();
        	partialMhd.setPromoted(mhd.isPromoted());
        }
        return partialMhd;
    }

    public MissionHealthPartialDetail saveLostTroopsShowMessage(PatientIdentifier patientIdentifier){
    	MissionHealthDetail mhd = getMissionHealthDetail(patientIdentifier);
        mhd.setLostTroopsShowMessage(false);
        mhd=missionHealthDataLayer.updateMissionHealthDetail(mhd);
        MissionHealthPartialDetail partialMhd=null;
        if(mhd.isLostTroopsShowMessage()==false){
	        partialMhd=new MissionHealthPartialDetail();
	        partialMhd.setLostTroopsShowMessage(mhd.isLostTroopsShowMessage());
        }
        return partialMhd;
    }

    public MissionHealthStandings getMissionHealthStandings(PatientIdentifier patientIdentifier, String standingType){
        MissionHealthDetail missionHealthDetail = missionHealthDataLayer.getMissionHealthDetail(patientIdentifier.getUniqueId());
        MissionHealthStandings standings = new MissionHealthStandings();
        if(null!= missionHealthDetail){
            if(null!=standingType && null!= StandingType.valueOf(standingType)){
                standings =  missionHealthDataLayer.getMissionHealthStandings(missionHealthDetail, StandingType.valueOf(standingType));
            }else{
                standings =  missionHealthDataLayer.getMissionHealthStandings(missionHealthDetail);
            }
        }
        return standings;
    }
    
    public AnnualServiceRollUp getAnnualServiceComparisonRollUp(){
    	AnnualServiceRollUp annualServiceRollUp=new AnnualServiceRollUp();
    	Map<String,Calendar> missionYearTimeFrame=MissionHealthTimeFrameService.getMissionYearTimeFrame(DateHelper.getToday());
    	annualServiceRollUp = missionHealthDataLayer.annualServiceComparisonRollUp(DateHelper.formatDateTimeInVistaFormat(missionYearTimeFrame.get("startDate").getTime()), annualServiceRollUp);
		if(annualServiceRollUp.getData()!=null && annualServiceRollUp.getData().size()>0){
	    	List<WeeklyServiceMetrics> tempAnnualServiceList=tieBreakerForAnnualServiceRollUp(annualServiceRollUp.getData());
	    	Collections.sort(tempAnnualServiceList,new ServiceAgeComparator());
		}
		long diff = missionYearTimeFrame.get("endDate").getTimeInMillis()-missionYearTimeFrame.get("beginningOfWeek").getTimeInMillis();
        float dayCount = (float) diff / (24 * 60 * 60 *1000);
        annualServiceRollUp.setWeeksLeft((int)(dayCount/7));	
    	return annualServiceRollUp;
    }
    
    public List<WeeklyServiceMetrics> tieBreakerForAnnualServiceRollUp(List<WeeklyServiceMetrics> annualServiceList){
    	int equalCounter=1;
		ArrayList<WeeklyServiceMetrics> tempAnnualServiceList=new ArrayList<WeeklyServiceMetrics>();
		tempAnnualServiceList.add(annualServiceList.get(0));
		WeeklyServiceMetrics v1=null;
		WeeklyServiceMetrics v2=null;
		for(int i=0;i<annualServiceList.size();i++){
			if(i+1<annualServiceList.size()){
				 v1=annualServiceList.get(i);
				 v2=annualServiceList.get(i+1);
			if(v1.getTotalPoints()==v2.getTotalPoints() && v1.getTotalMissionsCompleted()==v2.getTotalMissionsCompleted() && v1.getTotalTroops()==v2.getTotalTroops()){
				v2.setWinner(v1.getWinner());
				equalCounter=equalCounter+1;}
			else{
				if(equalCounter!=1)	{
				v2.setWinner(v1.getWinner()+equalCounter);
					equalCounter=1;
				}
			}
			tempAnnualServiceList.add(v2);
			}
		}
    	return tempAnnualServiceList;
    }
}
