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

import gov.va.med.esr.common.model.lookup.AssociationType;
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.AssociationInfo;
import gov.va.med.esr.voa.webservice.BaseAddressInfo;
import gov.va.med.fw.util.StringUtils;

import org.springframework.validation.Errors;

/**
 * Validate Association Information
 */
public class AssociationInfoValidator extends AbstractValidator {

	// less than 30 chars
	private static final int LIMIT_LESS_THAN_30_CHARS = 30;

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

	@Override
	public void validate(Object target, Errors errors) {
		logger.debug("Association info validation...");
		AssociationInfo associationInfo = (AssociationInfo) target;

		if (associationInfo != null) {
			String contactType = associationInfo.getContactType();
			String familyName = associationInfo.getFamilyName();
			String givenName = associationInfo.getGivenName();
			String phoneNumber = associationInfo.getPrimaryPhone();
			String alternatePhone = associationInfo.getAlternatePhone();

			BaseAddressInfo addressInfo = associationInfo.getAddress();
			if (AssociationType.CODE_EMERGENCY_CONTACT.getCode()
					.equalsIgnoreCase(contactType)) {
				// for emergency contact
				if(!this.isNewOMBApprovedForm){
					if (StringUtils.isBlank(familyName)) {
						errors.reject(ErrorCode.VOA_0049,
								"Missing Required Field: Emergency contact last name.");
					}
				}	
				if(!this.isNewOMBApprovedForm){
					if (StringUtils.isBlank(givenName)) {
						errors.reject(ErrorCode.VOA_0050,
								"Missing Required Field: Emergency contact first name.");
					}
				}

				if (addressInfo != null) {
					String line1 = addressInfo.getLine1();
					String city = addressInfo.getCity();
					String state = addressInfo.getState();
					String provinceCode = addressInfo.getProvinceCode();
					String zip = addressInfo.getZipCode();
					String zipPlus = addressInfo.getZipPlus4();
					String country = addressInfo.getCountry();

					if (StringUtils.isNotBlank(line1)
							&& line1.length() > LIMIT_LESS_THAN_30_CHARS) {
						errors.reject(ErrorCode.VOA_0051,
								"Invalid street address for Veteran's emergency contact.");
					}

					if (StringUtils.isNotBlank(city)
							&& city.length() > LIMIT_LESS_THAN_30_CHARS) {
						errors.reject(ErrorCode.VOA_0052,
								"Invalid City  for Veteran's emergency contact address.");
					}

					if (StringUtils.isBlank(country)) {
						errors.reject(ErrorCode.VOA_0242,
								"Missing required Field:  Country for Emergency contact address.");
						logger.debug("Missing required Field:  Country for Emergency contact address.");
					} else {
						try {
							getLookupService().getCountryByCode(country);
						} catch (Exception e) {
							errors.reject(ErrorCode.VOA_0225,
									"Invalid country for Emergency contact address.");
							logger.debug("Invalid country for Emergency contact address. "
									+ country + "\n" + e.getMessage());
						}

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

							if (StringUtils.isNotBlank(zip)) {
								boolean isValid = ServiceUtils.validateZip(zip);
								if (!isValid) {
									errors.reject(ErrorCode.VOA_0054,
											"Invalid Zip Code for emergency contact address.");
								}
							}

							if (StringUtils.isNotBlank(zipPlus)) {
								boolean isValid = ServiceUtils
										.validateZipPlus(zipPlus);
								if (!isValid) {
									errors.reject(ErrorCode.VOA_0232,
											"Invalid Zip Code for emergency contact address.");
								}
							}
						} else if (Country.CODE_CAN.getCode().equalsIgnoreCase(
								country)
								|| Country.CODE_MEX.getCode().equalsIgnoreCase(
										country)) {
							stateProvince = provinceCode;
						}

						// 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.isNotBlank(stateProvince)) {
								try {
									getLookupService().getStateByCode(
											stateProvince);
								} catch (Exception e) {
									errors.reject(ErrorCode.VOA_0053,
											"Invalid State or Province for Emergency contact address.");
									logger.debug("Invalid State or Province for Emergency contact address. "
											+ stateProvince
											+ "\n"
											+ e.getMessage());
								}
							}
						}
					}
				}
				
				String relationShip = associationInfo.getRelationship();
				if (StringUtils.isBlank(relationShip)) {
					if(!this.isNewOMBApprovedForm){
						errors.reject(ErrorCode.VOA_0055,
							"Missing Required Field:  Relationship for emergency contact.");
					}
				} else {
					boolean isValid = ServiceUtils.isAlphaNumeric(relationShip);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0222,
								"Invalid relationship value for Emergency Contact.");
						logger.debug("Invalid relationship value for Emergency Contact. "
								+ relationShip + "\n");
					}
				}

				if (phoneNumber != null) {
					boolean isValid = ServiceUtils.validatePhone(phoneNumber);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0056,
								"Invalid home telephone number for emergency contact.");
					}
				}

				if (StringUtils.isNotBlank(alternatePhone)) {
					boolean isValid = ServiceUtils
							.validatePhoneWithExtension(alternatePhone);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0057,
								"Invalid work telephone number for emergency contact.");
					}
				}
			} else if (AssociationType.CODE_PRIMARY_NEXT_OF_KIN.getCode()
					.equalsIgnoreCase(contactType)) {

				if(!this.isNewOMBApprovedForm)
				{
					if (StringUtils.isBlank(familyName)) {
						errors.reject(ErrorCode.VOA_0039,
								"Missing Required Field:  Next of kin last name.");
					}
				}
				if(!this.isNewOMBApprovedForm)
				{
					if (StringUtils.isBlank(givenName)) {
						errors.reject(ErrorCode.VOA_0040,
								"Missing Required Field: Next of kin first name.");
					}
				}

				if (addressInfo != null) {
					String line1 = addressInfo.getLine1();
					String city = addressInfo.getCity();
					String state = addressInfo.getState();
					String provinceCode = addressInfo.getProvinceCode();
					String zip = addressInfo.getZipCode();
					String zipPlus = addressInfo.getZipPlus4();
					String country = addressInfo.getCountry();

					if (StringUtils.isNotBlank(line1)
							&& line1.length() > LIMIT_LESS_THAN_30_CHARS) {
						errors.reject(ErrorCode.VOA_0041,
								"Invalid street address for next of kin.");
					}

					if (StringUtils.isNotBlank(city)
							&& city.length() > LIMIT_LESS_THAN_30_CHARS) {
						errors.reject(ErrorCode.VOA_0042,
								"Invalid City for next of kin address.");
					}

					if (StringUtils.isBlank(country)) {
						errors.reject(ErrorCode.VOA_0241,
								"Missing required Field: Country Next of Kin.");
						logger.debug("Missing required Field: Country Next of Kin.");
					} else {
						try {
							getLookupService().getCountryByCode(country);
						} catch (Exception e) {
							errors.reject(ErrorCode.VOA_0224,
									"Invalid country for Next of Kin address.");
							logger.debug("Invalid country for Next of Kin address. "
									+ country + "\n" + e.getMessage());
						}

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

							if (StringUtils.isNotBlank(zip)) {
								boolean isValid = ServiceUtils.validateZip(zip);
								if (!isValid) {
									errors.reject(ErrorCode.VOA_0044,
											"Invalid Zip Code for next of kin Address.");
								}
							}

							if (StringUtils.isNotBlank(zipPlus)) {
								boolean isValid = ServiceUtils
										.validateZipPlus(zipPlus);
								if (!isValid) {
									errors.reject(ErrorCode.VOA_0231,
											"Invalid Zip Code plus 4 for next of kin Address.");
								}
							}
						} else if (Country.CODE_CAN.getCode().equalsIgnoreCase(
								country)
								|| Country.CODE_MEX.getCode().equalsIgnoreCase(
										country)) {
							stateProvince = provinceCode;
						}

						// 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.isNotBlank(stateProvince)) {
								try {
									getLookupService().getStateByCode(
											stateProvince);
								} catch (Exception e) {
									errors.reject(ErrorCode.VOA_0043,
											"Invalid State or Province for Next of Kin state.");
									logger.debug("Invalid State or Province for Next of Kin state. "
											+ stateProvince
											+ "\n"
											+ e.getMessage());
								}
							}
						}
					}
				}

				// reference relationship
				String relationShip = associationInfo.getRelationship();
				if (StringUtils.isBlank(relationShip)) {
					if(!this.isNewOMBApprovedForm){
						errors.reject(ErrorCode.VOA_0045,
							"Missing Required Field: Relationship to veteran of next of kin.");
					}	
				} else {
					boolean isValid = ServiceUtils.isAlphaNumeric(relationShip);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0046,
								"Invalid relationship type for next of kin.");
						logger.debug("Invalid relationship type for next of kin. "
								+ relationShip + "\n");
					}
				}

				if (phoneNumber != null) {
					boolean isValid = ServiceUtils.validatePhone(phoneNumber);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0047,
								"Invalid next of kin home telephone number.");
					}
				}

				if (alternatePhone != null) {
					boolean isValid = ServiceUtils
							.validatePhoneWithExtension(alternatePhone);
					if (!isValid) {
						errors.reject(ErrorCode.VOA_0048,
								"Invalid next of kin work telephone number.");
					}
				}
			}
		}

		logger.debug("Association info validation - Done.");
	}
}
