package gov.cms.grouper.snf.process;

import com.mmm.his.cer.foundation.exception.FoundationException;
import gov.cms.grouper.snf.SnfComponentVersion;
import gov.cms.grouper.snf.SnfTables;
import gov.cms.grouper.snf.SnfComponentAbstract;
import gov.cms.grouper.snf.model.enums.SnfError;
import gov.cms.grouper.snf.model.SnfProcessError;
import gov.cms.grouper.snf.model.table.SnfVersionRow;
import gov.cms.grouper.snf.transfer.SnfClaim;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Map.Entry;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SnfProcessor {

  private static final Logger LOG = LoggerFactory.getLogger(SnfProcessor.class);

  protected SnfProcessor() { }

  protected static Integer getDataVersion(LocalDate date) {
    Integer version = null;

    for (Entry<Integer, SnfVersionRow> row : SnfTables.versions.entrySet()) {
      if (row.getValue().isDate(date)) {
        version = row.getKey();
        break;
      }
    }

    return version;
  }

  protected SnfClaim process(SnfClaim claim, Consumer<SnfClaim> finalProcessing)
      throws FoundationException, IOException {
      int correctDataVersion = getDataVersion(claim.getAssessmentReferenceDate());
      SnfComponentVersion releaseVersion = SnfComponentVersion.of(correctDataVersion);

      claim.setVersion(correctDataVersion);
      claim.setRecalculated_z0100b(SnfTables.getRecalculatedZ0100B());

      if (releaseVersion == null) {
        claim.addErrors(SnfError.INVALID_ASSESSMENT_REFERENCE_DATE.getReason());
      } else {
        try (SnfComponentAbstract snfComponent =
            releaseVersion.getCreateComponent().apply(correctDataVersion)) {
          // has to call process in order for KesselRun to work
          snfComponent.process(claim);
        } catch (SnfProcessError se) {
          LOG.debug(se.getMessage());
          throw se;
        } catch (Throwable th) {
          LOG.debug(th.getMessage());
          claim.addErrors(SnfError.PROCESS_ERROR.getReason(th.getMessage()));
          throw th;
        }
      }

    if (finalProcessing != null) {
      finalProcessing.accept(claim);
    }
    return claim;
  }
}
