
package de.ivu.elect.presentation.personenpruefung;

import static java.util.Arrays.asList;
import static org.apache.commons.lang3.StringUtils.defaultString;

import java.util.Collection;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.inject.Inject;

import de.ivu.elect.business.benutzerverwaltung.entity.Benutzer;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerEinsatzort;
import de.ivu.elect.business.gebietsbaum.entity.EntityMitGebiet;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.person.entity.PersonStatus;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.personenpruefung.boundary.PersonenKonfliktConversationSelect;
import de.ivu.elect.business.personenpruefung.boundary.PersonenKonfliktEdit;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonflikt;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktArt;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktMeta;
import de.ivu.elect.business.personenpruefung.entity.PersonenKonfliktStatus;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.control.ElectCommonPrincipal;
import de.ivu.elect.jee.faces.PreConditionCheck;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.jee.presentation.view.AbstractView;
import de.ivu.elect.presentation.security.GebietSecurity;
import de.ivu.elect.presentation.security.SperrmerkmalSecurity;
import de.ivu.elect.presentation.table.AbstractColumnEntry;

// BEI ANPASSUNGEN GGF. AUCH AbstractPersonenKonfliktDublettenAufloesenView ANPASSEN!!!
public abstract class AbstractPersonenKonfliktAufloesenView extends AbstractView implements PersonenKonfliktAufloesenView {

  private static final long serialVersionUID = 1L;

  @Inject
  protected transient ElectCommonPrincipal principal;

  @Inject
  protected transient GebietSecurity gebietSecurity;

  @Inject
  protected transient SperrmerkmalSecurity sperrmerkmalSecurity;

  @Inject
  protected transient PersonenKonfliktAufloesenViewViewAccessScopedStateStore viewAccessScopedState; // ELECT-8223

  @Inject
  protected transient PersonenKonfliktConversationSelect konfliktSelect;

  @Inject
  protected transient PersonenKonfliktEdit konfliktEdit;

  @Inject
  protected transient PersonenKonfliktMeta konfliktMeta;

  private String sperrmerkmalStyleClass;

  protected AbstractPersonenKonfliktAufloesenView() {
    super();
  }

  @PostConstruct
  public void init() {
    // To be overridden...
  }

  @PreConditionCheck
  public String checkPreCondition() {
    viewAccessScopedState.setEntity(getKonflikt());

    if (isKonfliktSelected() && isExpectedKonfliktArt(getExpectedKonfliktArt())) {
      return null;
    }

    return cancel();
  }

  public void preRenderView() {
    if (isPersonendatenAlreadyMarkedInvalid()) {
      addMessagePersonendatenAlreadyMarkedInvalid();
    }
  }

  private void addMessagePersonendatenAlreadyMarkedInvalid() {
    addWarningMessage("personen.konflikt.aufloesen.personendaten.already.invalid.message");
  }

  protected boolean isKonfliktSelected() {
    return getKonflikt() != null; // ELECT-8223
  }

  @Override
  public PersonenKonflikt getKonflikt() {
    return konfliktSelect.getEntity();
  }

  private boolean isExpectedKonfliktArt(PersonenKonfliktArt konfliktArt) {
    PersonenKonflikt konflikt = getKonflikt();

    if (konflikt != null) {
      return konfliktArt.equals(konflikt.getPersonenKonfliktArt());
    }

    return false;
  }

  public Personendaten getPersonendaten() {
    PersonenKonflikt konflikt = getKonflikt();

    if (konflikt != null) {
      return konflikt.getPersonendaten();
    }

    return null;
  }

  public String getPersonendatenStyleClass() {
    if (sperrmerkmalSecurity.isSperreVorhandenUndHervorzuheben(getKonflikt())) {
      return getSperrmerkmalStyleClass();
    }

    return "";
  }

  private String getSperrmerkmalStyleClass() {
    if (sperrmerkmalStyleClass == null) {
      sperrmerkmalStyleClass = defaultString(getMessage(AbstractColumnEntry.MSG_KEY_SPERRMERKMAL_STYLE_CLASS), "");
    }

    return sperrmerkmalStyleClass;
  }

  public boolean isBtnMarkPersonendatenInvalidRendered() {
    return !isReadonly() && hasKonfliktEditUseCasePermission() && !isPersonendatenAlreadyMarkedInvalid();
  }

  private boolean isPersonendatenAlreadyMarkedInvalid() {
    PersonenKonflikt konflikt = getKonflikt();

    if (konflikt != null && konflikt.isKonfliktStatusAblehnungsgrund()) {
      return konflikt.getPersonendaten().isPersonStatusNichtGeeignet();
    }

    return false;
  }

  public String getBtnMarkPersonendatenInvalidLabel() {
    return getMessage(getMarkPersonendatenInvalidMsgKey());
  }

  @Redirect
  public abstract String markPersonendatenInvalid();

  protected String markPersonendatenInvalidAndGoBack() {
    updatePersonendatenNichtGeeignetAndKonfliktAblehnungsgrund(getKonflikt());

    return clearKonfliktSelectedAndGoBack();
  }

  protected String getMarkPersonendatenInvalidMsgKey() {
    return "personen.konflikt.aufloesen.action.personendaten.NICHT_GEEIGNET.konflikt.IST_ABLEHNUNGSGRUND";
  }

  public boolean isBtnMarkPersonendatenValidRendered() {
    return !isReadonly() && hasKonfliktEditUseCasePermission() && !isPersonendatenAlreadyMarkedValid();
  }

  public boolean isBtnMarkPersonendatenValidDisabled() {
    return false;
  }

  private boolean isPersonendatenAlreadyMarkedValid() {
    PersonenKonflikt konflikt = getKonflikt();

    if (konflikt != null && konflikt.isKonfliktStatusIrrelevant()) {
      return konflikt.getPersonendaten().isPersonStatusGeeignet();
    }

    return false;
  }

  public String getBtnMarkPersonendatenValidLabel() {
    return getMessage(getMarkPersonendatenValidMsgKey());
  }

  @Redirect
  public abstract String markPersonendatenValid();

  protected String markPersonendatenValidAndGoBack() {
    updatePersonendatenGeeignetAndKonfliktIrrelevant(getKonflikt());

    return clearKonfliktSelectedAndGoBack();
  }

  protected String getMarkPersonendatenValidMsgKey() {
    return "personen.konflikt.aufloesen.action.personendaten.GEEIGNET.konflikt.IRRELEVANT";
  }

  protected void updatePersonendatenGeeignetAndKonfliktIrrelevant(PersonenKonflikt konflikt) {
    updatePersonendatenAndKonflikt(PersonStatus.GEEIGNET, PersonenKonfliktStatus.IRRELEVANT, konflikt);
  }

  protected void updatePersonendatenNichtGeeignetAndKonfliktAblehnungsgrund(PersonenKonflikt konflikt) {
    updatePersonendatenAndKonflikt(PersonStatus.NICHT_GEEIGNET, PersonenKonfliktStatus.IST_ABLEHNUNGSGRUND, konflikt);
  }

  protected void updatePersonendatenAndKonflikt(PersonStatus personStatus, PersonenKonfliktStatus konfliktStatus, PersonenKonflikt konflikt) {
    if (konflikt != null) {
      updatePersonendatenAndKonflikt(personStatus, konfliktStatus, asList(konflikt));
    }
  }

  protected void updatePersonendatenAndKonflikt(PersonStatus personStatus, PersonenKonfliktStatus konfliktStatus, Collection<PersonenKonflikt> konflikte) {
    // NOTE, dass der Konflikt UND DIE PERSONENDATEN vor dem Update der anderen Konflikte gespeichert werden müssen!
    konfliktEdit.saveAll(konflikte);
    konfliktEdit.updatePersonendatenAndKonflikt(personStatus, konfliktStatus, konflikte);

    addInfoMessage("personen.konflikt.aufloesen.action.personendaten." + personStatus.name() + ".konflikt." + konfliktStatus.name() + ".success.message");
  }

  public boolean isBtnCancelRendered() {
    return true;
  }

  @Redirect
  public String cancel() {
    return clearKonfliktSelectedAndGoBack();
  }

  protected String clearKonfliktSelectedAndGoBack() {
    konfliktSelect.clearEntity();

    return goBack(getParentViewId());
  }

  private boolean hasKonfliktEditUseCasePermission() {
    return hasPermission(getUseCasePermission());
  }

  protected abstract UseCasePermission getUseCasePermission();

  // Gebietsrechte beachten
  public boolean isReadonly() {
    if (!isKonfliktSelected()) {
      return true;
    }

    Personendaten personendaten = getPersonendaten();

    if (personendaten != null && personendaten.isInstanceOf(EntityMitGebiet.class)) {
      return !gebietSecurity.getBearbeitenGebietSecurity().isRechtVorhanden(personendaten.castTo(EntityMitGebiet.class).getEntity());
    }

    return false;
  }

  protected Mandant getMandant() {
    PersonenKonflikt konflikt = getKonflikt();

    if (konflikt != null) {
      Mandant mandant = konflikt.getMandant();

      if (mandant != null) {
        return mandant;
      }
    }

    return getPrincipal().getMandant();
  }

  protected ElectCommonPrincipal getPrincipal() {
    return principal;
  }

  @Nullable
  protected Benutzer getSelectedBenutzer() {
    return getPrincipal().getLogin();
  }

  protected String getSelectedBenutzerKennung() {
    return getPrincipal().getBenutzerKennung();
  }

  @Nullable
  protected BenutzerEinsatzort getSelectedBenutzerEinsatzort() {
    return getPrincipal().getBenutzerEinsatzort();
  }

  protected String getSelectedBenutzerNameFormatted() {
    return getPrincipal().getFormattedName();
  }

  protected boolean hasPermission(UseCasePermission permission) {
    return getPrincipal().hasUseCasePermission(permission);
  }
}
