package de.ivu.wahl.result.result;

import de.ivu.wahl.result.determination.GeneralList;
import de.ivu.wahl.result.determination.P2List;
import de.ivu.wahl.result.determination.P3List;

import java.util.Comparator;
import java.util.Objects;

public class GeneralListKey implements Comparable<GeneralListKey> {
  private static final String P2LIST_KEY_SEPARATOR = "_";

  private Integer listNumber;
  private Integer districtNumber;

  public GeneralListKey(Integer listNumber, Integer districtNumber) {
    this.listNumber = listNumber;
    this.districtNumber = districtNumber;
    assert listNumber != null || districtNumber == null;
  }

  static GeneralListKey from(GeneralList generalList) {
    if (generalList instanceof P2List) {
      return new GeneralListKey((P2List) generalList);
    } else if (generalList instanceof P3List) {
      return new GeneralListKey((P3List) generalList);
    } else {
      return new GeneralListKey();
    }
  }

  public GeneralListKey() {
    this(null, null);
  }

  public GeneralListKey(P2List p2List) {
    this(p2List.getFirstCandidateList().getListNumber(), p2List.getElectoralDistrictNumber());
  }

  public GeneralListKey(P3List p3List) {
    this(p3List.getListNumber(), null);
  }

  public Integer getListNumber() {
    return listNumber;
  }

  public Integer getDistrictNumber() {
    return districtNumber;
  }

  public boolean isP3Parent() {
    return listNumber == null;
  }

  public boolean isP3List() {
    return listNumber != null && districtNumber == null;
  }

  public boolean isP2List() {
    return listNumber != null && districtNumber != null;
  }

  public String getKey() {
    if (isP3Parent()) {
      return "";
    } else if (isP3List()) {
      return String.valueOf(listNumber);
    } else {
      return listNumber + P2LIST_KEY_SEPARATOR + districtNumber;
    }
  }

  @Override
  public int compareTo(GeneralListKey other) {
    return Comparator.comparingInt(GeneralListKey::getType)
            .thenComparing(GeneralListKey::getListNumber, Comparator.nullsFirst(Comparator.naturalOrder()))
            .thenComparing(GeneralListKey::getDistrictNumber, Comparator.nullsFirst(Comparator.naturalOrder()))
            .compare(this, other);
  }

  private int getType() {
    if (isP3Parent()) {
      return 0;
    } else if (isP3List()) {
      return 1;
    } else {
      return 2;
    }
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    GeneralListKey that = (GeneralListKey) o;
    return Objects.equals(listNumber, that.listNumber) && Objects.equals(districtNumber, that.districtNumber);
  }

  @Override
  public int hashCode() {
    return Objects.hash(listNumber, districtNumber);
  }

  @Override
  public String toString() {
    return "GeneralListKey{" + "listNumber='" + listNumber + '\'' + ", districtNumber='" + districtNumber + '\'' + '}';
  }
}
