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

import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.inject.Inject;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;

import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.staat.entity.AbstractStaat;
import de.ivu.elect.business.staat.entity.Staat;

public class StaatFinder implements Serializable {

  private static final long serialVersionUID = 1L;

  private static final String CUSTOM_CODE_INLAND = AbstractStaat.DEUTSCHLAND_CUSTOM_CODE;

  @Inject
  private transient StaatFactory staatFactory;

  public StaatFinder() {
    super();
  }

  public void tryAttachStaatsangehoerigkeitenOrIgnore(AbstractStaatDAO staatDAO, Personendaten personendaten) {
    // NOTE, dass bspw. ein Mapper immer 'leere' Staatsangehörigkeiten anlegt, anhand deren Werte die eigentlichen Staatsangehörigkeiten in der DB gefunden werden können!
    personendaten.setStaatsangehoerigkeitenSorted(tryFindUniqueStaatenOrIgnore(staatDAO, personendaten.getStaatsangehoerigkeitenSorted()));
  }

  public List<Staat> tryFindUniqueStaatenOrIgnore(AbstractStaatDAO staatDAO, List<Staat> staaten) {
    List<Staat> result = new ArrayList<>();

    for (Staat staat : staaten) {
      Staat found = tryFindUniqueStaat(staatDAO, staat);

      if (found != null) {
        result.add(found);
      }
    }

    return result;
  }

  public Staat tryFindUniqueStaat(AbstractStaatDAO staatDAO, String code) {
    Staat staatsangehoerigkeit = staatFactory.create();
    staatsangehoerigkeit.setCustomCodeStaatsangehoerigkeit(code);
    staatsangehoerigkeit.setIso3166Alpha2(code);

    return tryFindUniqueStaat(staatDAO, staatsangehoerigkeit);
  }

  public Staat tryFindUniqueStaat(AbstractStaatDAO staatDAO, Staat staat) {
    Staat result = null;

    if (staat != null) {
      if (staat.matchesInland()) {
        result = tryFindUniqueStaatByCustomCode(staatDAO, CUSTOM_CODE_INLAND, CUSTOM_CODE_INLAND);
      }

      if (result == null) {
        result = tryFindUniqueStaatByCustomCode(staatDAO, staat.getCustomCodeStaatsangehoerigkeit(), staat.getCustomCodeStaat());
      }

      if (result == null) {
        result = tryFindUniqueStaatByIso3166Alpha2(staatDAO, staat.getIso3166Alpha2());
      }

      if (result == null) {
        result = tryFindUniqueStaatByName(staatDAO, staat.getNameStaatsangehoerigkeit(), staat.getNameStaat());
      }
    }

    return result;
  }

  public Staat findUniqueStaatByLocale(AbstractStaatDAO staatDAO, Locale locale) {
    return findUniqueStaatsangehoerigkeitByIso3166Alpha2(staatDAO, locale.getCountry());
  }

  private Staat tryFindUniqueStaatByCustomCode(AbstractStaatDAO staatDAO, String customCodeStaatsangehoerigkeit, String customCodeStaat) {
    try {
      return findUniqueStaatByCustomCode(staatDAO, customCodeStaatsangehoerigkeit, customCodeStaat);
    } catch (IllegalArgumentException ignored) {
    }

    return null;
  }

  private Staat findUniqueStaatByCustomCode(AbstractStaatDAO staatDAO, String customCodeStaatsangehoerigkeit, String customCodeStaat) {
    String customCodeStaatsangehoerigkeitNormalized = normalizeCustomCode(customCodeStaatsangehoerigkeit);

    if (isNotBlank(customCodeStaatsangehoerigkeitNormalized)) {
      try {
        return staatDAO.findByUniqueCustomCodeStaatsangehoerigkeit(customCodeStaatsangehoerigkeitNormalized);
      } catch (NoResultException | NonUniqueResultException ignored) {
      }
    }

    String customCodeStaatNormalized = normalizeCustomCode(customCodeStaat);

    if (isNotBlank(customCodeStaatNormalized)) {
      try {
        return staatDAO.findByUniqueCustomCodeStaat(customCodeStaatNormalized);
      } catch (NoResultException | NonUniqueResultException ignored) {
      }
    }

    throw new IllegalArgumentException("Keinen eineindeutigen Staat gefunden [customCodeStaatsangehoerigkeit = " + customCodeStaatsangehoerigkeit + ", customCodeStaat = " + customCodeStaat + "]");
  }

  // ELECT-9167
  protected String normalizeCustomCode(String value) {
    String result = trimToEmpty(value).replaceAll("\\W", "");

    if (AbstractStaat.matchesInland(result)) {
      result = CUSTOM_CODE_INLAND;
    }

    return result;
  }

  private Staat tryFindUniqueStaatByIso3166Alpha2(AbstractStaatDAO staatDAO, String iso3166Alpha2) {
    try {
      return findUniqueStaatsangehoerigkeitByIso3166Alpha2(staatDAO, iso3166Alpha2);
    } catch (IllegalArgumentException ignored) {
    }

    return null;
  }

  private Staat findUniqueStaatsangehoerigkeitByIso3166Alpha2(AbstractStaatDAO staatDAO, String iso3166Alpha2) {
    if (isNotBlank(iso3166Alpha2)) {
      try {
        return staatDAO.findByUniqueIso3166Alpha2(iso3166Alpha2);
      } catch (NoResultException | NonUniqueResultException ignored) {
      }
    }

    throw new IllegalArgumentException("Keinen eineindeutigen Staat gefunden [iso3166Alpha2 = " + iso3166Alpha2 + "]");
  }

  private Staat tryFindUniqueStaatByName(AbstractStaatDAO staatDAO, String nameStaatsangehoerigkeit, String nameStaat) {
    try {
      return findUniqueStaatsangehoerigkeitByNameStaatsangehoerigkeit(staatDAO, nameStaatsangehoerigkeit, nameStaat);
    } catch (IllegalArgumentException ignored) {
    }

    return null;
  }

  private Staat findUniqueStaatsangehoerigkeitByNameStaatsangehoerigkeit(AbstractStaatDAO staatDAO, String nameStaatsangehoerigkeit, String nameStaat) {
    if (isNotBlank(nameStaatsangehoerigkeit)) {
      try {
        return staatDAO.findByUniqueNameStaatsangehoerigkeit(nameStaatsangehoerigkeit);
      } catch (NoResultException | NonUniqueResultException ignored) {
      }
    }

    if (isNotBlank(nameStaat)) {
      try {
        return staatDAO.findByUniqueNameStaat(nameStaat);
      } catch (NoResultException | NonUniqueResultException ignored) {
      }
    }

    throw new IllegalArgumentException("Keinen eineindeutigen Staat gefunden [nameStaatsangehoerigkeit = " + nameStaatsangehoerigkeit + ", nameStaat = " + nameStaat + "]");
  }
}
