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

import static org.apache.commons.lang3.StringUtils.deleteWhitespace;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.left;
import static org.apache.commons.lang3.StringUtils.leftPad;
import static org.apache.commons.lang3.StringUtils.rightPad;
import static org.apache.commons.lang3.StringUtils.startsWith;
import static org.apache.commons.lang3.StringUtils.substring;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.Objects;

import de.ivu.elect.business.gebietsbaum.entity.BundeslandKennzahl;

/**
 * Bspw. AGS8 München (gesamt) = 09 1 62 000...
 * <ul>
 * <li>1-2 = Kennung Bundesland</li>
 * <li>3 = Kennung Regierungsbezirk</li>
 * <li>4-5 = Kennung Landkreis oder kreisfreie Stadt</li>
 * <li>6-8 = Kennung Gemeinde (000 bei kreisfreier Stadt)</li>
 * </ul>
 * ... die Stelle 3-5 werden bei München als Nummer der Gemeinde hinterlegt.
 */
public class WahlverwaltungGemeindeAgs8 {

  public static final String KENNUNG_GEMEINDE_KREISFREIE_STADT = "000";

  private static final String KENNUNG_BUNDESLAND_FALLBACK = "  ";

  private final String nummerAgs8;

  public WahlverwaltungGemeindeAgs8(String nummer) {
    this(nummer, KENNUNG_BUNDESLAND_FALLBACK);
  }

  public WahlverwaltungGemeindeAgs8(String nummer, BundeslandKennzahl bundeslandKennzahl) {
    this(nummer, bundeslandKennzahl.getKennzahlFormatted());
  }

  public WahlverwaltungGemeindeAgs8(String nummer, String kennungBundesland) {
    super();

    this.nummerAgs8 = formatNummerAgs8(nummer, kennungBundesland);
  }

  public boolean hasKennungBundesland() {
    return !getGemeindeschluessel().startsWith(KENNUNG_BUNDESLAND_FALLBACK);
  }

  public String getKennungBundesland() {
    return substring(getGemeindeschluessel(), 0, 2);
  }

  /**
   * @return Der VOLLSTÄNDIGE Kreisschlüssel kodiert im AGS8, 5-stellig (== AGS8 ohne Kennung Gemeinde), also Kennung Bundesland (2) + Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie
   *         Stadt (2).
   *
   * @see WahlverwaltungGemeindeAgs8#getKreisschluesselRegionalangabe
   */
  public String getKreisschluessel() {
    return substring(getGemeindeschluessel(), 0, 5);
  }

  /**
   * @return Der REGIONALE Kreisschlüssel kodiert im AGS8, 3-stellig (== AGS8 ohne Kennungen Bundesland und Gemeinde), also Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2).
   *
   * @see WahlverwaltungGemeindeAgs8#getKreisschluessel
   */
  public String getKreisschluesselRegionalangabe() {
    return substring(getGemeindeschluesselRegionalangabe(), 0, 3);
  }

  /**
   * @return Der VOLLSTÄNDIGE Gemeindeschlüssel kodiert im AGS8, 8-stellig, also Kennung Bundesland (2) + Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2) + Kennung Gemeinde
   *         (3).
   *
   * @see WahlverwaltungGemeindeAgs8#getGemeindeschluesselRegionalangabe
   */
  public String getGemeindeschluessel() {
    return nummerAgs8;
  }

  /**
   * @return Die REGIONALE Gemeindeschlüssel kodiert im AGS8, 6-stellig (== AGS8 ohne Kennung Bundesland), also Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2) + Kennung
   *         Gemeinde (3).
   *
   * @see WahlverwaltungGemeindeAgs8#getGemeindeschluessel
   */
  public String getGemeindeschluesselRegionalangabe() {
    return substring(getGemeindeschluessel(), 2);
  }

  private static String formatNummerAgs8(String nummer, String kennungBundeslandFallback) {
    String nummerNormalized = trimToEmpty(deleteWhitespace(nummer));

    String nummerSystematikCustomer = formatNummerAgs8SystematikCustomer(nummerNormalized, kennungBundeslandFallback);

    if (isNotBlank(nummerSystematikCustomer) && !Objects.equals(nummerSystematikCustomer, nummerNormalized)) {
      return nummerSystematikCustomer;
    }

    int length = nummerNormalized.length();

    // Kennung Bundesland (2) + Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2) + Kennung Gemeinde (3)
    if (length == 8) {
      return nummerNormalized;
    }

    // Kennung Bundesland (1) + Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2) + Kennung Gemeinde (3)
    if (length == 7) {
      return formatKennungBundesland(left(nummerNormalized, 1)) + substring(nummerNormalized, 1);
    }

    // Kennung Bundesland (2) + Kennung Regierungsbezirk (1) + Kennung kreisfreie Stadt (2)
    if (length == 5) {
      return nummerNormalized + KENNUNG_GEMEINDE_KREISFREIE_STADT;
    }

    // Kennung Bundesland (1) + Kennung Regierungsbezirk (1) + Kennung kreisfreie Stadt (2)
    if (length == 4) {
      return formatKennungBundesland(left(nummerNormalized, 1)) + substring(nummerNormalized, 1) + KENNUNG_GEMEINDE_KREISFREIE_STADT;
    }

    String kennungBundeslandFallbackFormatted = formatKennungBundesland(kennungBundeslandFallback);

    // Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2) + Kennung Gemeinde (3)
    if (length == 6) {
      return kennungBundeslandFallbackFormatted + nummerNormalized;
    }

    // Kennung Regierungsbezirk (1) + Kennung kreisfreie Stadt (2)
    if (length == 3) {
      return kennungBundeslandFallbackFormatted + nummerNormalized + KENNUNG_GEMEINDE_KREISFREIE_STADT;
    }

    return rightPad(kennungBundeslandFallbackFormatted, 8, "0"); // Nullen nach rechts auffüllen
  }

  private static String formatNummerAgs8SystematikCustomer(String nummerNormalized, String kennungBundeslandFallback) {
    String kennungBundeslandFallbackFormatted = formatKennungBundesland(kennungBundeslandFallback);

    if (BundeslandKennzahl.BRANDENBURG.getKennzahlFormatted().equals(kennungBundeslandFallbackFormatted)) {
      return formatNummerAgs8SystematikBb(nummerNormalized);
    }

    return nummerNormalized;
  }

  private static String formatNummerAgs8SystematikBb(String nummerNormalized) {
    String kennungBundeslandFormatted = BundeslandKennzahl.BRANDENBURG.getKennzahlFormatted();

    String nummer = nummerNormalized;

    if (!startsWith(nummer, kennungBundeslandFormatted)) {
      nummer = kennungBundeslandFormatted + nummer;
    }

    int length = nummer.length();
    String kreisschluessel = substring(nummer, 0, 5); // Kennung Bundesland (2) + Kennung Regierungsbezirk (1) + Kennung Landkreis oder kreisfreie Stadt (2)

    if (length == 9 || length == 13) { // Amt || Briefwahlbezirk in Amt
      return rightPad(kreisschluessel, 8, "0");
    }

    if (length == 12) { // Gemeinde
      return kreisschluessel + substring(nummer, -3);
    }

    if (length == 16) { // Urnenwahlbezirk
      return kreisschluessel + substring(nummer, 9, 12);
    }

    return nummerNormalized;
  }

  private static String formatKennungBundesland(String nummer) {
    String nummerNormalized = deleteWhitespace(nummer);
    String padCharacter = " ";

    if (isNotBlank(nummerNormalized)) {
      padCharacter = "0";
    }

    return leftPad(nummerNormalized, 2, padCharacter);
  }
}
