package gov.cms.grouper.snf.process;

import com.mmm.his.cer.foundation.exception.FoundationException;
import gov.cms.grouper.snf.SnfComponentAbstract;
import gov.cms.grouper.snf.SnfComponentVersion;
import gov.cms.grouper.snf.SnfContext;
import gov.cms.grouper.snf.SnfTables;
import gov.cms.grouper.snf.model.Assessment;
import gov.cms.grouper.snf.model.enums.Rai300;
import gov.cms.grouper.snf.model.enums.SnfError;
import gov.cms.grouper.snf.transfer.SnfClaim;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Consumer;

public class SnfProcessor {

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

  private static final Map<Rai300, Rai300> fy2024Updates = new HashMap<Rai300, Rai300>() {{
    put(Rai300.D0160, Rai300.D0300);
    put(Rai300.K0520A2, Rai300.K0510A1);
    put(Rai300.K0520A3, Rai300.K0510A2);
    put(Rai300.K0520B2, Rai300.K0510B1);
    put(Rai300.K0520B3, Rai300.K0510B2);
    put(Rai300.K0520C3, Rai300.K0510C2);
    put(Rai300.O0110A1B, Rai300.O0100A2);
    put(Rai300.O0110B1B, Rai300.O0100B2);
    put(Rai300.O0110C1B, Rai300.O0100C2);
    put(Rai300.O0110D1B, Rai300.O0100D2);
    put(Rai300.O0110E1B, Rai300.O0100E2);
    put(Rai300.O0110F1B, Rai300.O0100F2);
    put(Rai300.O0110H1B, Rai300.O0100H2);
    put(Rai300.O0110I1B, Rai300.O0100I2);
    put(Rai300.O0110J1B, Rai300.O0100J2);
    put(Rai300.O0110M1B, Rai300.O0100M2);
  }};


  protected SnfProcessor() {
  }

  protected SnfClaim process(SnfClaim claim, Consumer<SnfClaim> finalProcessing)
      throws FoundationException, IOException {
    LOG.debug("Start of claim: {} ===============================================================", claim.getClaimId());
    Integer correctDataVersion = SnfContext.trace("Grouper version based on " + claim.getAssessmentReferenceDate(),
            SnfTables.getDataVersion(claim.getAssessmentReferenceDate()));
    SnfComponentVersion releaseVersion = SnfContext.trace(SnfComponentVersion.of(correctDataVersion));

    if (releaseVersion == null) {
      claim.addErrors(SnfError.INVALID_ASSESSMENT_REFERENCE_DATE.getReason(
              String.valueOf(claim.getAssessmentReferenceDate())));
    } else {

      claim.setVersion(correctDataVersion);
      claim.setRecalculated_z0100b(SnfTables.getRecalculatedZ0100B());
      claim.setMdsRaiVersion(SnfTables.getItemSetVersion(claim.getAssessmentReferenceDate()));

      retiredItemSetUpdate(correctDataVersion, claim);

      try (SnfComponentAbstract snfComponent =
               releaseVersion.getCreateComponent().apply(correctDataVersion)) {
        // has to call process in order for KesselRun to work
        snfComponent.process(claim);
      } catch (Throwable th) {
        // For NI to show errors
//        claim.addErrors(Arrays.toString(th.getStackTrace()));
        LOG.error(Arrays.toString(th.getStackTrace()));
        throw th;
      }
    }

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

    LOG.debug("End of claim: {} =================================================================\n\n", claim.getClaimId());
    return claim;
  }

  protected void retiredItemSetUpdate(int dataVersion, SnfClaim snfClaim) {
    Map<String, Assessment> assessmentMap = snfClaim.getAssessmentMap();

    if (dataVersion >= SnfProcessor.FY2024_VERSION) {
      for (Entry<Rai300, Rai300> update : fy2024Updates.entrySet()) {
        Rai300 newItem = update.getKey();
        Rai300 oldItem = update.getValue();

        if (assessmentMap.containsKey(newItem.getXmlTag())) {
          Assessment hybridAssessment = new Assessment(oldItem.name(), oldItem.getXmlTag(), assessmentMap.get(newItem.getXmlTag()));
          assessmentMap.put(oldItem.getXmlTag(), hybridAssessment);
        }
      }
      LOG.debug("Mapped old RAI300 to new");
    }
  }
}
