package com.agilex.healthcare.schedulingmanager.validator;

import com.agilex.healthcare.mobilehealthplatform.domain.ValidationError;
import com.agilex.healthcare.mobilehealthplatform.domain.ValidationErrors;
import com.agilex.healthcare.schedulingmanager.domain.SMAppointmentRequest;
import com.agilex.healthcare.schedulingmanager.enumeration.AppointmentRequestType;
import com.agilex.healthcare.utility.DateHelper;

import java.util.*;

public class AppointmentRequestValidatorHelper {
	
	public static boolean isValidAppointmentType(String appointmentType) {
		List<String> validAppointmentTypes = new LinkedList<String>();
		
		for (AppointmentRequestType type : AppointmentRequestType.values()) {
			validAppointmentTypes.add(type.getName());
		}
		
		if (validAppointmentTypes.contains(appointmentType) == false) {
			return false;
		}
		
		return true;
	}

	
	public static ValidationErrors<SMAppointmentRequest> validateUniqueOptions(SMAppointmentRequest SMAppointmentRequest, String optionDate1, String optionDate2, String optionDate3) {
		ValidationErrors<SMAppointmentRequest> errors = new ValidationErrors<SMAppointmentRequest>();
		ValidationError optionDate1Error = null;
		ValidationError optionDate2Error = null;
		ValidationError optionDate3Error = null;
		
		if (!(SMAppointmentRequest.getOptionTime1().equalsIgnoreCase("No Time Selected") && SMAppointmentRequest.getOptionTime2().equalsIgnoreCase("No Time Selected")) && areOptionsEqual(SMAppointmentRequest.getOptionDate1(), SMAppointmentRequest.getOptionTime1(), SMAppointmentRequest.getOptionDate2(), SMAppointmentRequest.getOptionTime2())) {
			optionDate1Error = createNonUniqueDatePreferenceErrorMessage(optionDate1);
			optionDate2Error = createNonUniqueDatePreferenceErrorMessage(optionDate2);
			
		}
		if (!(SMAppointmentRequest.getOptionTime1().equalsIgnoreCase("No Time Selected") && SMAppointmentRequest.getOptionTime3().equalsIgnoreCase("No Time Selected")) && areOptionsEqual(SMAppointmentRequest.getOptionDate1(), SMAppointmentRequest.getOptionTime1(), SMAppointmentRequest.getOptionDate3(), SMAppointmentRequest.getOptionTime3())) {
			optionDate1Error = createNonUniqueDatePreferenceErrorMessage(optionDate1);
			optionDate3Error = createNonUniqueDatePreferenceErrorMessage(optionDate3);
		}
		if (!(SMAppointmentRequest.getOptionTime3().equalsIgnoreCase("No Time Selected") && SMAppointmentRequest.getOptionTime2().equalsIgnoreCase("No Time Selected")) && areOptionsEqual(SMAppointmentRequest.getOptionDate3(), SMAppointmentRequest.getOptionTime3(), SMAppointmentRequest.getOptionDate2(), SMAppointmentRequest.getOptionTime2())) {
			optionDate3Error = createNonUniqueDatePreferenceErrorMessage(optionDate3);
			optionDate2Error = createNonUniqueDatePreferenceErrorMessage(optionDate2);
		}
		
		errors.addIfNotNull(optionDate1Error);
		errors.addIfNotNull(optionDate2Error);
		errors.addIfNotNull(optionDate3Error);
		
		return errors;
	}
	
	private static ValidationError createNonUniqueDatePreferenceErrorMessage(String fieldName) {
		String errorMessage = "Date preference must be unique.";
		
		ValidationError validationError = new ValidationError();
		validationError.setFieldName(fieldName);
		validationError.setErrorMessage(errorMessage);
		
		return validationError;
	}
	
	private static boolean areOptionsEqual(String date1, String time1, String date2, String time2) {
		boolean result = false;
		
		if (date1.equals(date2)) {
			if (time1.equals(time2)) {
				result = true;
			}
		}
		
		return result;
	}
	
	public static ValidationError validateMinDateBusinessLogic(int minHours, int fieldNumber, String optionDate, String optionTime) {
		
		
		String field = String.format("Option %s", fieldNumber);
		ValidationError error = null;
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR, minHours);
		
		boolean passingWeekend = false;
		while (calendar.get(Calendar.DAY_OF_WEEK) == 1 || calendar.get(Calendar.DAY_OF_WEEK) == 7) { 
			calendar.add(Calendar.DATE, 1);
			passingWeekend = true;
		}
		
		if (passingWeekend) {
			calendar.set(Calendar.HOUR, 9);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			calendar.set(Calendar.AM_PM, 0);
		}
		
		Date minDate = calendar.getTime();
		Date option = parseOption(optionDate, optionTime);
		if (option.before(minDate)) {
			error = new ValidationError();
			error.setFieldName(field);
			error.setErrorMessage(String.format("Requested date must be after %s hours and on a business day.", minHours));
		}
		return error;
	}

	public static ValidationError validateMaxDateBusinessLogic(int maxDays, int fieldNumber, String optionDate, String optionTime) {
		String field = String.format("Option %s", fieldNumber);
		ValidationError error = null;
		Date maxDate = DateHelper.plusDays(new Date(), maxDays);
		Date option = parseOption(optionDate, optionTime);
		if (option.after(maxDate)) {
			error = new ValidationError();
			error.setFieldName(field);
			error.setErrorMessage(String.format("Requested date must be within the next %s calendar days.", maxDays));
		}
		return error;
	}
	
	public static Date parseOption(String date, String time) {
		Calendar cal = new GregorianCalendar();
		cal.setTime(DateHelper.parseDate(date));
		
		if (time.trim().equalsIgnoreCase("AM")) {
			cal.set(Calendar.HOUR, 9);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.MILLISECOND, 0);
			cal.set(Calendar.AM_PM, 0);
		} else {
			cal.set(Calendar.HOUR, 12);
			cal.set(Calendar.MINUTE, 0);
			cal.set(Calendar.SECOND, 0);
			cal.set(Calendar.MILLISECOND, 0);
			cal.set(Calendar.AM_PM, 1);
		}
		
		return cal.getTime();
	}
}
