package de.ivu.elect.business.gebietsbaum.entity;

import static org.apache.commons.lang3.StringUtils.capitalize;
import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.lowerCase;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.Arrays;

public enum Verwaltungsart {

  OHNE {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }

    @Override
    public boolean isGesetzt() {
      return false;
    }
  },

  /**
   * ELECTBB-475, Gebietsgruppierung aus "einem" Briefwahlbezirk, der mit seinen zugehörigen Urnenwahlbezirken zusammengefasst ist...
   */
  BRIEFWAHLBEZIRK_GEBIET {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  WAHLKREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },
  STIMMKREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },
  WAHLBEREICH {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },
  BEIRATSBEREICH {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },
  ORTSBEIRATSBEREICH {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },

  ERFASSUNGSGEBIET {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  BUNDESLAND {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  /**
   * Landkreis/Kreisfreie Stadt
   */
  KREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  VERWALTUNGSGEMEINSCHAFT {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  VERBANDSGEMEINDE {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  GEMEINDE {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  ORTSBEZIRK { // ELECT-13692

    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  STADTBEZIRK {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  STADTTEIL {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  ORTSTEIL {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  /**
   * BB und BE, falls aktuelle Wahl NICHT "Bundestagswahl"...
   */
  BUNDESTAGSWAHLKREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },

  /**
   * Nur BE...
   */
  BERLIN_OST_WEST {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  /**
   * Nur BE, a.k.a. "Stadtbezirk"...
   */
  BEZIRK {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  /**
   * Bei den Verwaltungsbezirken ist die Position relevant für die Reihenfolge, in der diese z.B. im Wahlbuch angezeigt werden...
   *
   * @deprecated ELECTBB-157, wird nur noch an einer Stelle verwendet, cf. BbbGebietMitErgebnisdatenInklVorperiodeDokument#erstelleStimmenAllerUntergebietsgruppen...
   */
  VERWALTUNGSBEZIRK {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  LANDTAGSWAHLKREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },
  ABGEORDNETENHAUSWAHLKREIS {
    @Override
    public boolean isWahlgebietTeilraum() {
      return true;
    }
  },

  TEILSTADTBEZIRK {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  ORTSCHAFT {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  ORTSAMT {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  SAMTGEMEINDE {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  AMT {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  ORTSBEREICH {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },
  LAND {
    @Override
    public boolean isWahlgebietTeilraum() {
      return false;
    }
  },

  ;

  public boolean isGesetzt() {
    return true;
  }

  /**
   * @return Bspw. "Wahlkreis", "Stimmkreis", "Wahlbereich", ...
   */
  public abstract boolean isWahlgebietTeilraum();
  
  public boolean equalsGebietsart(Gebiet gebiet) {
    return gebiet != null && equalsGebietsart(gebiet.getGebietsart());
  }

  public boolean equalsGebietsart(Gebietsart gebietsart) {
    String gebietsartNameOderTitel = name();

    return gebietsart != null && (equalsIgnoreCase(gebietsart.getName(), gebietsartNameOderTitel) || equalsIgnoreCase(gebietsart.getTitel(), gebietsartNameOderTitel));
  }

  public boolean equalsGebietsgruppierungArt(Gebietsgruppierung gebietsgruppierung) {
    return equalsGebietsgruppierungArt(this, gebietsgruppierung);
  }

  static boolean equalsGebietsgruppierungArt(Verwaltungsart gebietsgruppierungArt, Gebietsgruppierung gebietsgruppierung) {
    return gebietsgruppierung != null && equalsArt(gebietsgruppierungArt, gebietsgruppierung.getVerwaltungsart());
  }

  static boolean equalsArt(Verwaltungsart one, Verwaltungsart another) {
    return one != null && one.equals(another);
  }

  static boolean equalsArt(Verwaltungsart one, String another) {
    return equalsArt(one.name(), another);
  }

  public static Verwaltungsart fromString(String name) {
    if (isBlank(name)) {
      return Verwaltungsart.OHNE;
    }

    return Arrays.stream(Verwaltungsart.values())
        .filter(value -> equalsArt(value, name))
        .findFirst()
        .orElse(Verwaltungsart.OHNE);
  }

  public String toDisplayName() {
    return capitalize(lowerCase(name()));
  }

  static boolean equalsArt(String one, String another) {
    return isNotBlank(one) && trimToEmpty(one).equalsIgnoreCase(trimToEmpty(another));
  }
}
