package gov.cms.grouper.snf.model.table;

import gov.cms.grouper.snf.lego.CsvBuilder;
import gov.cms.grouper.snf.lego.Pair;
import gov.cms.grouper.snf.lego.SnfComparator;
import gov.cms.grouper.snf.lego.SnfUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;

public class NtaCmgRow extends BasicRow {

  public static final BiFunction<NtaCmgRow, Pair<Integer, Integer>, Boolean> verScoreFilter =
      (row, pair) -> {
        int version = pair.getOne();
        int score = pair.getTwo();
        boolean correctVer = BasicRow.versionSelector.apply(row, version);
        boolean between =
            SnfComparator.betweenInclusive(row.getLowScore(), score, row.getHighScore());
        return correctVer && between;
      };

  private String cmg;
  private Integer lowScore;
  private Integer highScore;

  private NtaCmgRow() {
    this(null, null, null);
  }

  public NtaCmgRow(String cmg, Integer lowScore, Integer highScore) {
    this.cmg = cmg;
    this.lowScore = lowScore;
    this.highScore = highScore;
  }

  public String getCmg() {
    return this.cmg;
  }

  public Integer getLowScore() {
    return this.lowScore;
  }

  public Integer getHighScore() {
    return this.highScore;
  }

  public void setCmg(String cmg) {
    this.cmg = cmg;
  }

  public void setLowScore(Integer lowScore) {
    this.lowScore = lowScore;
  }

  public void setHighScore(Integer highScore) {
    this.highScore = highScore;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = super.getHashCode(result, prime);
    result = prime * result + ((this.cmg == null) ? 0 : this.cmg.hashCode());
    result = prime * result + ((this.highScore == null) ? 0 : this.highScore.hashCode());
    result = prime * result + ((this.lowScore == null) ? 0 : this.lowScore.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (this.getClass() != obj.getClass()) {
      return false;
    }
    NtaCmgRow other = (NtaCmgRow) obj;
    if (super.equals(other) == false) {
      return false;
    }

    if (this.cmg == null) {
      if (other.cmg != null) {
        return false;
      }
    } else if (!this.cmg.equals(other.cmg)) {
      return false;
    }
    if (this.highScore == null) {
      if (other.highScore != null) {
        return false;
      }
    } else if (!this.highScore.equals(other.highScore)) {
      return false;
    }
    if (this.lowScore == null) {
      if (other.lowScore != null) {
        return false;
      }
    } else if (!this.lowScore.equals(other.lowScore)) {
      return false;
    }
    return true;
  }

  public static class Builder extends CsvBuilder<NtaCmgRow> {

    private static final BiConsumer<NtaCmgRow, String> cmg =
        (rowModel, value) -> rowModel.cmg = SnfUtils.clean(value);

    private static final BiConsumer<NtaCmgRow, String> lowScore =
        (rowModel, value) -> rowModel.lowScore = SnfUtils.parse(value, null);

    private static final BiConsumer<NtaCmgRow, String> highScore =
        (rowModel, value) -> rowModel.highScore = SnfUtils.parse(value, null);

    private Builder() {
      super(NtaCmgRow::new, Builder.initCsvMapping());
    }

    private static Map<Integer, BiConsumer<NtaCmgRow, String>> initCsvMapping() {
      Map<Integer, BiConsumer<NtaCmgRow, String>> result = new HashMap<>();
      result.put(0, Builder.cmg);
      result.put(1, BasicRow.getLowVersionParser());
      result.put(2, BasicRow.getHighVersionParser());
      result.put(3, Builder.lowScore);
      result.put(4, Builder.highScore);

      return Collections.unmodifiableMap(result);
    }

    private static final Builder singleton = new Builder();

    public static NtaCmgRow.Builder of() {
      return Builder.singleton;
    }
  }

}
