package com.agilex.healthcare.schedulingmanager.datalayer.appointment;

import com.agilex.healthcare.schedulingmanager.datalayer.FacilityPo;
import com.agilex.healthcare.schedulingmanager.datalayer.PersistenceObject;
import com.agilex.healthcare.schedulingmanager.datalayer.Transformable;
import com.agilex.healthcare.schedulingmanager.datalayer.patient.PatientPo;
import com.agilex.healthcare.schedulingmanager.domain.SMAppointmentRequest;
import com.agilex.healthcare.schedulingmanager.domain.SMAppointmentRequestDetailCode;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.util.*;

@Entity
@Table(name = AppointmentRequestPo.TABLE_NAME)
@XStreamAlias("SMAppointmentRequest")
public class AppointmentRequestPo extends PersistenceObject implements Transformable<SMAppointmentRequest> {
	private static final long serialVersionUID = 1285362900973753379L;
	public static final String TABLE_NAME = "APPOINTMENT_REQUEST";

	private Date createdDate;
	private Date lastUpdatedDate;
	private Date deletedDate;
	private boolean activeFlag = true;
	private boolean secondRequest;

	private String appointmentDate;
	private String appointmentTime;
	private String optionDate1;
	private String optionTime1;
	private String optionDate2;
	private String optionTime2;
	private String optionDate3;
	private String optionTime3;
	
	private String status;
	private String appointmentType;
	private String visitType;
	private FacilityPo facility;
	private String email;
	private boolean textMessagingAllowed;
	private String textMessagingPhoneNumber;
	private String phoneNumber;
	private String purposeOfVisit;
	private String otherPurposeOfVisit;
	
	private String providerId;
	private String providerName;
	private String providerPersonClass;
	private String providerOption;
	
	private boolean secondRequestSubmitted;
	
	private AppointmentRequestPo parentRequest;
	private PatientPo patient;
	
	@XStreamImplicit(itemFieldName="BestTimeToCall")
	private Set<String> bestTimetoCall = new HashSet<String>();
	
	@XStreamImplicit(itemFieldName="SMAppointmentRequestDetailCode")
	private List<AppointmentRequestDetailCodePo> appointmentRequestDetailCode = new LinkedList<AppointmentRequestDetailCodePo>();
	
	private boolean hasVeteranNewMessage;
	private boolean hasProviderNewMessage;
	private boolean providerSeenAppointmentRequest;
	
	private boolean requestedPhoneCall;
	
	private Date bookedApptDateTime;

	public AppointmentRequestPo() {	
	}
	
	public AppointmentRequestPo(SMAppointmentRequest dto) {
		setActiveFlag(dto.isActiveFlag());
		setAppointmentRequestId(dto.getAppointmentRequestId());
		setVisitType(dto.getVisitType());
		setAppointmentType(dto.getAppointmentType());
		setCreatedDate(dto.getCreatedDate());
		setDeletedDate(dto.getDeletedDate());
		setEmail(dto.getEmail());
		setFacility(new FacilityPo(dto.getFacility()));
		setOptionDate1(dto.getOptionDate1());
		setOptionTime1(dto.getOptionTime1());
		setOptionDate2(dto.getOptionDate2());
		setOptionTime2(dto.getOptionTime2());
		setOptionDate3(dto.getOptionDate3());
		setOptionTime3(dto.getOptionTime3());
		setPhoneNumber(dto.getPhoneNumber());
		setLastUpdatedDate(dto.getLastUpdatedDate());
		setStatus(dto.getStatus());
		setId(dto.getUniqueId());
		setBestTimetoCall(dto.getBestTimetoCall());
		setPurposeOfVisit(dto.getPurposeOfVisit());
		setOtherPurposeOfVisit(dto.getOtherPurposeOfVisit());
		setProviderId(dto.getProviderId());
		setProviderName(dto.getProviderName());
		setProviderPersonClass(dto.getProviderPersonClass());
		setProviderOption(dto.getProviderOption());
		setSecondRequest(dto.isSecondRequest());
		setAppointmentDate(dto.getAppointmentDate());
		setAppointmentTime(dto.getAppointmentTime());
		setAppointmentRequestDetailCode(toPo(dto.getAppointmentRequestDetailCode()));
		
		setPatient(new PatientPo(dto.getPatient()));
		setTextMessagingAllowed(dto.isTextMessagingAllowed());
		setTextMessagingPhoneNumber(dto.getTextMessagingPhoneNumber());
		
		setSecondRequestSubmitted(dto.isSecondRequestSubmitted());

        setHasProviderNewMessage(dto.isHasProviderNewMessage());
        setHasVeteranNewMessage(dto.isHasVeteranNewMessage());
        setProviderSeenAppointmentRequest(dto.isProviderSeenAppointmentRequest());
		setRequestedPhoneCall(dto.isRequestedPhoneCall());
		setBookedApptDateTime(dto.getBookedApptDateTime());
		for (AppointmentRequestDetailCodePo arDetailCodePo: getAppointmentRequestDetailCode()) {
			arDetailCodePo.setAppointmentRequest(this);
		}
		
		if (dto.getParentRequest() != null){
			AppointmentRequestPo parentRequestPo = new AppointmentRequestPo(dto.getParentRequest());
			setParentRequest(parentRequestPo);
		}
	}

	public List<AppointmentRequestDetailCodePo> toPo(List<SMAppointmentRequestDetailCode> dtos) {
		List<AppointmentRequestDetailCodePo> po = new LinkedList<AppointmentRequestDetailCodePo>();
		
		for (SMAppointmentRequestDetailCode dto : dtos) {
			po.add(new AppointmentRequestDetailCodePo(dto));
		}
		
		return po;
	}
	
	@Id
	@GeneratedValue(generator="appointment_request_id_generator")
	@GenericGenerator(name="appointment_request_id_generator", strategy = "uuid")
	@Column(name = "APPOINTMENT_REQUEST_ID")
	public String getAppointmentRequestId() {
		return super.getId();
	}
	
	public void setAppointmentRequestId(String appointmentRequestId) {
		super.setId(appointmentRequestId);
	}

	@Column(name = "CREATED_DATE")
	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	@Column(name = "LAST_UPDATED_DATE")
	public Date getLastUpdatedDate() {
		return lastUpdatedDate;
	}

	public void setLastUpdatedDate(Date lastUpdatedDate) {
		this.lastUpdatedDate = lastUpdatedDate;
	}

	@Column(name = "DELETED_DATE")
	public Date getDeletedDate() {
		return deletedDate;
	}

	public void setDeletedDate(Date deletedDate) {
		this.deletedDate = deletedDate;
	}

	@Column(name = "ACTIVE")
	public boolean isActiveFlag() {
		return activeFlag;
	}

	public void setActiveFlag(boolean activeFlag) {
		this.activeFlag = activeFlag;
	}

	@Column(name = "APPOINTMENT_DATE")
	public String getAppointmentDate() {
		return appointmentDate;
	}

	public void setAppointmentDate(String appointmentDate) {
		this.appointmentDate = appointmentDate;
	}
	
	@Column(name = "APPOINTMENT_TIME")
	public String getAppointmentTime() {
		return appointmentTime;
	}
	
	public void setAppointmentTime(String appointmentTime) {
		this.appointmentTime = appointmentTime;
	}

	@Column(name = "OPTION_DATE_1")
	public String getOptionDate1() {
		return optionDate1;
	}

	public void setOptionDate1(String optionDate1) {
		this.optionDate1 = optionDate1;
	}
	
	@Column(name = "OPTION_TIME_1")
	public String getOptionTime1() {
		return optionTime1;
	}

	public void setOptionTime1(String optionTime1) {
		this.optionTime1 = optionTime1;
	}

	@Column(name = "OPTION_DATE_2")
	public String getOptionDate2() {
		return optionDate2;
	}

	public void setOptionDate2(String optionDate2) {
		this.optionDate2 = optionDate2;
	}
	
	@Column(name = "OPTION_TIME_2")
	public String getOptionTime2() {
		return optionTime2;
	}

	public void setOptionTime2(String optionTime2) {
		this.optionTime2 = optionTime2;
	}

	@Column(name = "OPTION_DATE_3")
	public String getOptionDate3() {
		return optionDate3;
	}

	public void setOptionDate3(String optionDate3) {
		this.optionDate3 = optionDate3;
	}
	
	@Column(name = "OPTION_TIME_3")
	public String getOptionTime3() {
		return optionTime3;
	}

	public void setOptionTime3(String optionTime3) {
		this.optionTime3 = optionTime3;
	}
	
	@Column(name = "STATUS")
	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	@Column(name = "APPOINTMENT_TYPE")
	public String getAppointmentType() {
		return appointmentType;
	}

	public void setAppointmentType(String appointmentType) {
		this.appointmentType = appointmentType;
	}
	
	@Column(name = "VISIT_TYPE")
	public String getVisitType() {
		return visitType;
	}
	
	public void setVisitType(String visitType) {
		this.visitType = visitType;
	}

	@Column(name = "EMAIL")
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Column(name = "PHONE_NUMBER")
	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	@ElementCollection(fetch=FetchType.EAGER)
	@CollectionTable(
	        name="BEST_TIME_TO_CALL",
	        joinColumns=@JoinColumn(name="APPOINTMENT_REQUEST_ID")
	)
	@Column(name="BEST_TIME")
	public Set<String> getBestTimetoCall() {
		return bestTimetoCall;
	}

	public void setBestTimetoCall(Set<String> bestTimetoCall) {
		this.bestTimetoCall = bestTimetoCall;
	}

	@Column(name = "PURPOSE_OF_VISIT")
	public String getPurposeOfVisit() {
		return purposeOfVisit;
	}

	public void setPurposeOfVisit(String purposeOfVisit) {
		this.purposeOfVisit = purposeOfVisit;
	}

	@Column(name = "OTHER_PURPOSE_OF_VISIT")
	public String getOtherPurposeOfVisit() {
		return otherPurposeOfVisit;
	}

	public void setOtherPurposeOfVisit(String otherPurposeOfVisit) {
		this.otherPurposeOfVisit = otherPurposeOfVisit;
	}

	@Column(name = "PROVIDER_ID")
	public String getProviderId() {
		return providerId;
	}

	public void setProviderId(String providerId) {
		this.providerId = providerId;
	}

	@Column(name = "PROVIDER_NAME")
	public String getProviderName() {
		return providerName;
	}

	public void setProviderName(String providerName) {
		this.providerName = providerName;
	}

	@Column(name = "PROVIDER_PERSON_CLASS")
	public String getProviderPersonClass() {
		return providerPersonClass;
	}

	public void setProviderPersonClass(String providerPersonClass) {
		this.providerPersonClass = providerPersonClass;
	}
	
	@Column(name = "PROVIDER_OPTION")
	public String getProviderOption() {
		return providerOption;
	}
	
	public void setProviderOption(String providerOption) {
		this.providerOption = providerOption;
	}

	@Column(name = "SECOND_REQUEST")
	public boolean isSecondRequest() {
		return secondRequest;
	}

	public void setSecondRequest(boolean secondRequest) {
		this.secondRequest = secondRequest;
	}

	@OrderBy("createdDate DESC")
	@OneToMany(targetEntity = AppointmentRequestDetailCodePo.class, mappedBy = "appointmentRequest", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
	public List<AppointmentRequestDetailCodePo> getAppointmentRequestDetailCode() {
		return appointmentRequestDetailCode;
	}

	public void setAppointmentRequestDetailCode(List<AppointmentRequestDetailCodePo> appointmentRequestDetailCode) {
		this.appointmentRequestDetailCode = appointmentRequestDetailCode;
	}

	@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = FacilityPo.class, fetch = FetchType.EAGER)
	@JoinColumn(name="FACILITY_CODE", nullable=false, updatable=false)
	public FacilityPo getFacility() {
		return facility;
	}

	public void setFacility(FacilityPo facility) {
		this.facility = facility;
	}

	@Column(name = "SECOND_REQUEST_SUBMITTED")
	public boolean isSecondRequestSubmitted() {
		return secondRequestSubmitted;
	}

	public void setSecondRequestSubmitted(boolean secondRequestSubmitted) {
		this.secondRequestSubmitted = secondRequestSubmitted;
	}

	@OneToOne(cascade=CascadeType.ALL)
	@JoinColumn(name="PARENT_REQUEST_ID")
	public AppointmentRequestPo getParentRequest() {
		return parentRequest;
	}

	public void setParentRequest(AppointmentRequestPo parentRequest) {
		this.parentRequest = parentRequest;
	}

	@Column(name = "TEXT_MESSAGING_ALLOWED", nullable = false)
	public boolean isTextMessagingAllowed() {
		return textMessagingAllowed;
	}

	public void setTextMessagingAllowed(boolean textMessagingAllowed) {
		this.textMessagingAllowed = textMessagingAllowed;
	}

	@Column(name = "TEXT_MESSAGING_PHONE_NUMBER")
	public String getTextMessagingPhoneNumber() {
		return textMessagingPhoneNumber;
	}

	public void setTextMessagingPhoneNumber(String textMessagingPhoneNumber) {
		this.textMessagingPhoneNumber = textMessagingPhoneNumber;
	}

	@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = PatientPo.class, fetch = FetchType.EAGER)
	@JoinColumn(name="PATIENT_ID", nullable=false)
	public PatientPo getPatient() {
		return patient;
	}

	public void setPatient(PatientPo patient) {
		this.patient = patient;
	}

	@Column(name = "HAS_VETERAN_NEW_MESSAGE")
	public boolean isHasVeteranNewMessage() {
		return hasVeteranNewMessage;
	}

	public void setHasVeteranNewMessage(boolean hasVeteranNewMessage) {
		this.hasVeteranNewMessage = hasVeteranNewMessage;
	}

	@Column(name = "HAS_PROVIDER_NEW_MESSAGE")
	public boolean isHasProviderNewMessage() {
		return hasProviderNewMessage;
	}

	public void setHasProviderNewMessage(boolean hasProviderNewMessage) {
		this.hasProviderNewMessage = hasProviderNewMessage;
	}

	@Column(name = "PROVIDER_SEEN_APPT_REQ")
	public boolean isProviderSeenAppointmentRequest() {
		return providerSeenAppointmentRequest;
	}

	public void setProviderSeenAppointmentRequest(
			boolean providerSeenAppointmentRequest) {
		this.providerSeenAppointmentRequest = providerSeenAppointmentRequest;
	}

	@Column(name = "REQUESTED_PHONE_CALL")
	public boolean isRequestedPhoneCall() {
		return requestedPhoneCall;
	}

	public void setRequestedPhoneCall(boolean requestedPhoneCall) {
		this.requestedPhoneCall = requestedPhoneCall;
	}
	
	@Column(name = "BOOKED_APPT_DATETIME")
	public Date getBookedApptDateTime() {
		return bookedApptDateTime;
	}

	public void setBookedApptDateTime(Date bookedApptDateTime) {
		this.bookedApptDateTime = bookedApptDateTime;
	}

	@Override
	public SMAppointmentRequest create() {
		SMAppointmentRequest dto = new SMAppointmentRequest();

		dto.setActiveFlag(isActiveFlag());
		dto.setAppointmentRequestId(getAppointmentRequestId());
		dto.setAppointmentType(getAppointmentType());
		dto.setVisitType(getVisitType());
		dto.setCreatedDate(getCreatedDate());
		dto.setDeletedDate(getDeletedDate());
		dto.setEmail(getEmail());
		dto.setFacility(getFacility().create());
		dto.setOptionDate1(getOptionDate1());
		dto.setOptionTime1(getOptionTime1());
		dto.setOptionDate2(getOptionDate2());
		dto.setOptionTime2(getOptionTime2());
		dto.setOptionDate3(getOptionDate3());
		dto.setOptionTime3(getOptionTime3());
		dto.setPhoneNumber(getPhoneNumber());
		dto.setLastUpdatedDate(getLastUpdatedDate());
		dto.setStatus(getStatus());
		dto.setUniqueId(getId());
		dto.setBestTimetoCall(getBestTimetoCall());
		dto.setPurposeOfVisit(getPurposeOfVisit());
		dto.setOtherPurposeOfVisit(getOtherPurposeOfVisit());
		dto.setProviderId(getProviderId());
		dto.setProviderName(getProviderName());
		dto.setProviderPersonClass(getProviderPersonClass());
		dto.setProviderOption(getProviderOption());
		
		dto.setPatient(getPatient().create());
		dto.setPatientId(getPatient().getUserId());
		dto.setTextMessagingAllowed(isTextMessagingAllowed());
		dto.setTextMessagingPhoneNumber(getTextMessagingPhoneNumber());
		
		dto.setSecondRequest(isSecondRequest());
		
		dto.setAppointmentDate(getAppointmentDate());
		dto.setAppointmentTime(getAppointmentTime());
		
		dto.setSecondRequestSubmitted(isSecondRequestSubmitted());
		
		
		dto.setAppointmentRequestDetailCode(toDto(getAppointmentRequestDetailCode()));
		dto.setHasProviderNewMessage(isHasProviderNewMessage());
		dto.setHasVeteranNewMessage(isHasVeteranNewMessage());
		dto.setProviderSeenAppointmentRequest(isProviderSeenAppointmentRequest());
		dto.setRequestedPhoneCall(isRequestedPhoneCall());
		dto.setBookedApptDateTime(getBookedApptDateTime());
		return dto;
	}

	private List<SMAppointmentRequestDetailCode> toDto(List<AppointmentRequestDetailCodePo> pos) {
		List<SMAppointmentRequestDetailCode> dto = new LinkedList<SMAppointmentRequestDetailCode>();
		
		for (AppointmentRequestDetailCodePo po : pos) {
			dto.add(po.create());
		}
		
		return dto;
	}	
}
