package gov.cms.grouper.snf.process;

import gov.cms.grouper.snf.SnfContext;
import gov.cms.grouper.snf.model.Assessment;
import gov.cms.grouper.snf.model.AssessmentType;
import gov.cms.grouper.snf.model.reader.Rai300;
import gov.cms.grouper.snf.transfer.ISnfClaim;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SnfValidations {

  private static final Logger log = LoggerFactory.getLogger(SnfValidations.class);
  private static final Pattern pattern =
      Pattern.compile("([A-Za-z][0-9][0-9A-Za-z]\\.[0-9A-Za-z^]{4})|(\\^)");
  private final ISnfClaim snfClaim;

  public SnfValidations(ISnfClaim snfClaim) {
    this.snfClaim = snfClaim;
  }

  public static void validateInputs(ISnfClaim snfClaim) {
    if (validateDiagnosisPattern(snfClaim.getPrimaryDiagnosis().getValue()) == false) {
      SnfContext.trace("Invalid principal diagnosis code pattern");

    } else if (validateAssessments(snfClaim.getAssessments()) == false) {
      SnfContext.trace("Invalid assessment value");
    }

  }

  /**
   * Since some of the valid value is range based some are not, we use special logic: treating the
   * first two values as its range and the following are also valid. So if a value is between it's
   * first two values or matches any of the following values, it's valid.
   */
  protected static boolean validateAssessments(final List<Assessment> assessments) {
    boolean isAllValueValid = true;
    List<Assessment> assessmentList = assessments.stream().filter((assessment) -> {
      boolean result = false;
      AssessmentType assessmentType = Rai300.valueOf(assessment.getItem()).getAssessmentType();

      if ((assessmentType != AssessmentType.PPS && assessmentType != AssessmentType.ARD
          && assessmentType != AssessmentType.SERVICES && assessmentType != AssessmentType.HIPPS)
          && assessment.getValueInt() != Assessment.NULL_VALUE) {
        result = true;
      }
      return result;
    }).collect(Collectors.toList());

    for (Assessment assessment : assessmentList) {
      List<Integer> validValues = Rai300.valueOf(assessment.getItem()).getValidValues();

      if ((assessment.getValueInt() <= validValues.get(0)
          || assessment.getValueInt() >= validValues.get(1))
          && validValues.contains(assessment.getValueInt()) == false) {
        log.warn(assessment.getItem() + " " + assessment.getValueInt());
        isAllValueValid = false;
      }
    }

    return isAllValueValid;
  }

  protected static boolean validateDiagnosisPattern(String code) {
    final char caret = '^';
    // Check pattern with regex; condition a - e
    boolean isMatch = SnfValidations.pattern.matcher(code).matches();

    // Check ^, condition f; not sure how to check this with regex otherwise
    if (isMatch) {
      int caretIndex = code.indexOf(caret);
      if (caretIndex != -1) {
        for (int i = caretIndex; i < code.length(); i++) {
          if (code.charAt(i) != caret) {
            return false;
          }
        }
      }
    }

    return isMatch;
  }
}
