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.AddressInfo;
import gov.va.med.esr.voa.webservice.InsuranceInfo;
import gov.va.med.fw.util.StringUtils;

import org.springframework.validation.Errors;

/**
 * Validate Insurance Information
 */
public class InsuranceInfoValidator extends AbstractValidator {

	private static final String INSURANCE_TYPE_PRIVATE = "PI";
	private static final String INSURANCE_TYPE_MEDICARE = "MDCR";

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

	@Override
	public void validate(Object target, Errors errors) {
		if (logger.isDebugEnabled())
			logger.debug("InsuranceInfo validation...");

		if (target != null) {
			InsuranceInfo insuranceInfo = (InsuranceInfo) target;

			String policyNumber = insuranceInfo.getPolicyNumber();
			String insuranceMappingType = insuranceInfo
					.getInsuranceMappingTypeName();
			if (INSURANCE_TYPE_PRIVATE.equalsIgnoreCase(insuranceMappingType)) {
				// Private insurance
				String companyName = insuranceInfo.getCompanyName();
				if (StringUtils.isBlank(companyName)) {
					errors.reject(ErrorCode.VOA_0059,
							"Missing Required Field: Name of Insurance Company.");
				}

				AddressInfo addressInfo = insuranceInfo.getInsAddress();
				validateAddress(addressInfo, errors);

				String policyHolderName = insuranceInfo.getPolicyHolderName();
				if (StringUtils.isBlank(policyHolderName)) {
					errors.reject(ErrorCode.VOA_0065,
							"Missing Required Field:  Name of Insurance policy holder.");
				}

				String groupNumber = insuranceInfo.getGroupNumber();

				if (StringUtils.isBlank(policyNumber)
						&& StringUtils.isBlank(groupNumber)) {
					errors.reject(ErrorCode.VOA_0066,
							"Missing Required Field:  Insurance policy number or group code.");
				}
			} else if (INSURANCE_TYPE_MEDICARE
					.equalsIgnoreCase(insuranceMappingType)) {
				// MEDICARE insurance
				Boolean isEnrolledInPartA = insuranceInfo.isEnrolledInPartA();
				String partAEffectiveDate = insuranceInfo
						.getPartAEffectiveDate();
				if (isEnrolledInPartA == null) {
					errors.reject(ErrorCode.VOA_0069,
							"Missing Required Field: Medicare Insurance Part A enrollment.");
				} else if (isEnrolledInPartA.booleanValue()) {
					if (StringUtils.isBlank(partAEffectiveDate)) {
						errors.reject(
								ErrorCode.VOA_0070,
								"Missing Required Field: Effective date of Medicare Insurance Part A enrollment.");
					} else {
						boolean isValid = ServiceUtils
								.validateDate(partAEffectiveDate);
						if (!isValid) {
							errors.reject(ErrorCode.VOA_0071,
									"Invalid Medicare part A effective date.");
						} else {
							boolean isFutureDate = ServiceUtils
									.isFutureDate(partAEffectiveDate);
							if (isFutureDate) {
								errors.reject(ErrorCode.VOA_0071,
										"Invalid Medicare part A effective date.");
							}
						}
					}
				}

			}
		}
		if (logger.isDebugEnabled())
			logger.debug("InsuranceInfo validation - Done.");
	}

	/**
	 * validate insurance company address
	 *
	 * @param addressInfo
	 * @param errors
	 */
	public void validateAddress(AddressInfo addressInfo, Errors errors) {
		logger.debug("AddressInfo validation...");

		if (addressInfo != null) {
			String line1 = addressInfo.getLine1();

			if (StringUtils.isNotBlank(line1)
					&& line1.length() > ServiceUtils.LIMIT_LESS_THAN_35_CHARS) {
				errors.reject(ErrorCode.VOA_0060,
						"Invalid street address for Insurance company.");
			}

			String city = addressInfo.getCity();
			if (StringUtils.isNotBlank(city)
					&& city.length() > ServiceUtils.LIMIT_LESS_THAN_25_CHARS) {
				errors.reject(ErrorCode.VOA_0061,
						"Invalid City for Insurance company address.");
			}


			/** CCR 13724 - default country to USA if empty country field with a valid zip
				//This statement is not valid anymore: If no zip code, and no country, it should be an error. See note below for Defect # 317751
				If valid zip code is there, then address is domestic, default to USA.
			*/
			String zip = addressInfo.getZipCode();
			String country = addressInfo.getCountry();

			//RTC Defect # 317751 - for 1010EZR, if both country and zip are blank, set USA as the default country
			if (StringUtils.isBlank(country) && StringUtils.isBlank(zip)) {
				try {
					getLookupService().getCountryByCode(Country.CODE_USA.getCode());
				} catch (Exception e) {
					errors.reject(ErrorCode.VOA_0226,
							"Invalid country provided for insurance company.");
					if (logger.isDebugEnabled())
						logger.debug("Invalid country for insurance company. "
							+ country + "\n" + e.getMessage());
				}
			}
			else {
				try {
					if (StringUtils.isNotBlank(zip)){
						if (getLookupService().getZipCodeByCode(zip) != null){
							getLookupService().getCountryByCode(Country.CODE_USA.getCode());
						}
						else
						{
						  errors.reject(ErrorCode.VOA_0063, "Invalid zip code for insurance company.");
						}
					}
					else if (StringUtils.isBlank(zip) && StringUtils.isNotBlank(country)){
						getLookupService().getCountryByCode(country);
					}
				} catch (Exception e) {
					errors.reject(ErrorCode.VOA_0226,
							"Invalid country for insurance company.");
					if (logger.isDebugEnabled())
						logger.debug("Invalid country for insurance company. "
							+ country + "\n" + e.getMessage());
				}

				String stateProvince = null;
				if (Country.CODE_USA.getCode().equalsIgnoreCase(country)) {
					stateProvince = addressInfo.getState();
					zip = addressInfo.getZipCode();
					if (StringUtils.isNotBlank(zip)) {
						boolean isValid = ServiceUtils.validateZip(zip);
						if (!isValid) {
							errors.reject(ErrorCode.VOA_0063,
									"Invalid zip code for insurance company.");
							if (logger.isDebugEnabled())
								logger.debug("Invalid zip code for insurance company. "
										+ zip);
						}
					}

					String zipPlus = addressInfo.getZipPlus4();
					if (StringUtils.isNotBlank(zipPlus)) {
						boolean isValid = ServiceUtils.validateZipPlus(zipPlus);
						if (!isValid) {
							errors.reject(ErrorCode.VOA_0233,
									"Invalid zip code plus 4 for insurance company.");
							if (logger.isDebugEnabled())
								logger.debug("Invalid zip code plus 4 for insurance company. "
									+ zip);
						}
					}
				} 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.isNotBlank(stateProvince)) {
						try {
							getLookupService().getStateByCode(stateProvince);
						} catch (Exception e) {
							errors.reject(ErrorCode.VOA_0062,
									"Invalid state or province for insurance company.");
							if (logger.isDebugEnabled())
								logger.debug("Invalid state or province for insurance company. "
									+ stateProvince + "\n" + e.getMessage());
						}
					}
				}
			}

			String phoneNumber = addressInfo.getPhoneNumber();
			if (StringUtils.isNotBlank(phoneNumber)) {
				boolean isValid = ServiceUtils.validatePhone(phoneNumber);
				if (!isValid) {
					errors.reject(ErrorCode.VOA_0064,
							"Invalid phone number for insurance company.");
					if (logger.isDebugEnabled())
						logger.debug("Invalid phone number for insurance company. "
							+ phoneNumber);
				}
			}
		}
		if (logger.isDebugEnabled())
			logger.debug("AddressInfo validation - Done.");
	}

}
