package gov.va.med.esr.voa.validator;

import gov.va.med.esr.common.model.lookup.Country;
import gov.va.med.esr.voa.common.ErrorCode;
import gov.va.med.esr.voa.util.ServiceUtils;
import gov.va.med.esr.voa.webservice.AddressCollection;
import gov.va.med.esr.voa.webservice.AddressInfo;
import gov.va.med.esr.voa.webservice.ContactInfo;
import gov.va.med.esr.voa.webservice.DemographicInfo;
import gov.va.med.esr.voa.webservice.EmailCollection;
import gov.va.med.esr.voa.webservice.EmailInfo;
import gov.va.med.esr.voa.webservice.PhoneCollection;
import gov.va.med.esr.voa.webservice.PhoneInfo;
import gov.va.med.fw.util.StringUtils;

import java.util.List;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;

/**
 * Validate demographic information
 */
public class DemographicInfoValidator extends AbstractValidator {

	@SuppressWarnings("rawtypes")
	@Override
	public boolean supports(Class clazz) {
		return DemographicInfo.class.equals(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {
		logger.debug("Validate Demographic information.");

		if (target != null) {
			DemographicInfo demographicInfo = (DemographicInfo) target;

			String maritalStatus = demographicInfo.getMaritalStatus();
			if (StringUtils.isBlank(maritalStatus)) {
				errors.reject(ErrorCode.VOA_0016, "Missing Required Field.");
			} else {
				try {
					// this is status code from input.
					getLookupService().getMaritalStatusByCode(maritalStatus);
				} catch (Exception e) {
					errors.reject(ErrorCode.VOA_0017, "Invalid Marital Status.");
					logger.debug("Cannot find marital status. "
							+ e.getMessage());
				}
			}

			String preferredFacility = demographicInfo.getPreferredFacility();
			if (StringUtils.isBlank(preferredFacility)) {
				errors.reject(ErrorCode.VOA_0020,
						"Missing Required Field: Preferred VA Facility.");
			} else {
				try {
					// this is preferredFacility is code from input.
					getLookupService().getVaFacilityByCode(preferredFacility);
				} catch (Exception e) {
					errors.reject(ErrorCode.VOA_0021, "Invalid VA Facility.");
					logger.debug("Invalid VA Facility. " + preferredFacility
							+ "\n" + e.getMessage());
				}
			}

			String ethnicityCode = demographicInfo.getEthnicity();
			try {
				getLookupService().getEthnicityTypeByCode(ethnicityCode);
			} catch (Exception e) {
				errors.reject(ErrorCode.VOA_0022,
						"Not a valid reference value.");
				logger.debug("Not a valid reference value. " + e.getMessage());
			}

			String religion = demographicInfo.getReligion();
			try {
				getLookupService().getReligionByCode(religion);
			} catch (Exception e) {
				errors.reject(ErrorCode.VOA_0029, "Invalid religion.");
				logger.debug("Not a valid reference value. " + e.getMessage());
			}

			ContactInfo contactInfo = demographicInfo.getContactInfo();

			if (contactInfo != null) {
				// validate address
				AddressCollection addressCollection = contactInfo
						.getAddresses();
				if (addressCollection != null) {
					List<AddressInfo> addressInfoList = addressCollection
							.getAddress();
					for (AddressInfo addressInfo : addressInfoList) {
						validateAddress(addressInfo, errors);
					}
				}

				// validate email.
				EmailCollection emailCollection = contactInfo.getEmails();
				if (emailCollection != null) {
					List<EmailInfo> emailInfoList = emailCollection.getEmail();
					for (EmailInfo emailInfo : emailInfoList) {
						ValidationUtils.invokeValidator(
								new EmailInfoValidator(), emailInfo, errors);
					}
				}

				// validation phone
				PhoneCollection phoneCollection = contactInfo.getPhones();
				if (phoneCollection != null) {
					List<PhoneInfo> phoneInfoList = phoneCollection.getPhone();
					for (PhoneInfo phoneInfo : phoneInfoList) {
						ValidationUtils.invokeValidator(
								new PhoneInfoValidator(), phoneInfo, errors);
					}
				}
			}
			
			if (demographicInfo.isAcaIndicator() == null) {
				errors.reject(ErrorCode.VOA_0252, "Missing required field: COVERAGE UNDER THE AFFORDABLE CARE ACT");
			}
		}

		logger.debug("Validate Demographic information - Done.");
	}

	/**
	 * Validate address info
	 * 
	 * @param addressInfo
	 * @param errors
	 */
	private void validateAddress(AddressInfo addressInfo, Errors errors) {
		logger.debug("AddressInfo validation...");

		if (addressInfo != null) {
			String line1 = addressInfo.getLine1();
			if (StringUtils.isBlank(line1)) {
				errors.reject(ErrorCode.VOA_0030,
						"Missing required Field:  Street for Veteran Permanent Address.");
			}

			String city = addressInfo.getCity();
			if (StringUtils.isBlank(city)) {
				errors.reject(ErrorCode.VOA_0031,
						"Missing required Field:  City for Veteran Permanent Address.");
			}

			String country = addressInfo.getCountry();
			if (StringUtils.isBlank(country)) {
				errors.reject(ErrorCode.VOA_0240,
						"Missing required Field: Country for Veteran Permanent Address.");
				logger.debug("Missing required Field: Country for Veteran Permanent Address.");
			} else {
				try {
					getLookupService().getCountryByCode(country);
				} catch (Exception e) {
					errors.reject(ErrorCode.VOA_0223,
							"Invalid country for Veteran Permanent Address.");
					logger.debug("Invalid country for Veteran Permanent Address. "
							+ e.getMessage());
				}

				String stateProvince = null;
				if (Country.CODE_USA.getCode().equalsIgnoreCase(country)) {
					stateProvince = addressInfo.getState();

					String zip = addressInfo.getZipCode();
					if (StringUtils.isBlank(zip)) {
						errors.reject(ErrorCode.VOA_0034,
								"Missing Required Field: Veteran Permanent Address Zip Code.");
					} else {
						boolean isValid = ServiceUtils.validateZip(zip);
						if (!isValid) {
							errors.reject(ErrorCode.VOA_0035,
									"Invalid Zip Code for  Veteran Permanent Address.");
						}
					}

					String zipPlus = addressInfo.getZipPlus4();
					if (StringUtils.isNotBlank(zipPlus)) {
						boolean isValid = ServiceUtils.validateZipPlus(zipPlus);
						if (!isValid) {
							errors.reject(ErrorCode.VOA_0230,
									"Invalid Zip Code plus 4 for  Veteran Permanent Address.");
						}
					}
				} else if (Country.CODE_CAN.getCode().equalsIgnoreCase(country)
						|| Country.CODE_MEX.getCode().equalsIgnoreCase(country)) {
					stateProvince = addressInfo.getProvinceCode();
				}

				// only check state of USA or province of CAN & MEX
				if (Country.CODE_USA.getCode().equalsIgnoreCase(country)
						|| Country.CODE_CAN.getCode().equalsIgnoreCase(country)
						|| Country.CODE_MEX.getCode().equalsIgnoreCase(country)) {
					if (StringUtils.isBlank(stateProvince)) {
						errors.reject(ErrorCode.VOA_0032,
								"Missing required Field: State or Province for Veteran Permanent Address.");
					} else {
						try {
							getLookupService().getStateByCode(stateProvince);
						} catch (Exception e) {
							errors.reject(ErrorCode.VOA_0033,
									"Invalid State or Province for Veteran Permanent Address.");
							logger.debug("Invalid State or Province for Veteran Permanent Address. "
									+ stateProvince + " " + e.getMessage());
						}
					}
				}
			}
		}

		logger.debug("AddressInfo validation - Done.");
	}
}
