
package de.ivu.elect.presentation.interfaces;

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

import java.util.List;
import java.util.UUID;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.konfiguration.entity.ElectKonfigurationWerte;
import de.ivu.elect.business.konfiguration.entity.KonfigurationExtendedLoader;
import de.ivu.elect.business.konfiguration.entity.MandantKonfigurationWerte;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.control.ElectCommonPrincipal;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.AdvancedDynaFormModel;
import de.ivu.elect.jee.presentation.dynamicform.DynamicFormEditOrCreateView;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.ReadOnlyStringProperty;
import de.ivu.elect.jee.presentation.redirect.Redirect;
import de.ivu.elect.jee.presentation.view.AbstractView;

public abstract class AbstractInterfacesInterfaceTestView<T> extends AbstractView implements DynamicFormEditOrCreateView {

  private static final long serialVersionUID = 1L;

  private static final Logger LOGGER = LoggerFactory.getLogger(AbstractInterfacesInterfaceTestView.class);

  @Inject
  private transient ElectCommonPrincipal principal;

  @Inject
  private transient KonfigurationExtendedLoader konfigurationExtendedLoader;

  private AdvancedDynaFormModel interfaceParametersModel;

  protected UUID requestUUID;

  protected String serviceUUID;

  protected AbstractInterfacesInterfaceTestView() {
    super();
  }

  public abstract String getViewId();

  protected abstract UseCasePermission getRequiredPermission();

  protected abstract String getInterfaceName();

  public abstract List<T> getInterfaceResult();

  protected void resetModel() {
    interfaceParametersModel = null;
  }

  @Override
  public AdvancedDynaFormModel getModel() {
    if (interfaceParametersModel == null) {
      FormBuilder formBuilder = new FormBuilder();

      addProperties(getMandant(), formBuilder);

      if (requestUUID != null || isNotBlank(serviceUUID)) {
        formBuilder.addSeparator();

        if (requestUUID != null) {
          formBuilder.addProperty(new ReadOnlyStringProperty("Request-UUID", requestUUID.toString())).withTooltip("Eindeutige ID zu Test- und Analysezwecken, bspw. zur Nachverfolgung in Logausgaben");
        }

        if (isNotBlank(serviceUUID) && (requestUUID == null || !equalsIgnoreCase(serviceUUID, requestUUID.toString()))) {
          formBuilder.addProperty(new ReadOnlyStringProperty("Service-UUID", serviceUUID));
        }
      }

      interfaceParametersModel = formBuilder.createModel();
    }

    return interfaceParametersModel;
  }

  protected abstract void addProperties(Mandant mandant, FormBuilder formBuilder);

  protected String resolveStringValue(MandantKonfigurationWerte mandantKonfigurationWerte) {
    return konfigurationExtendedLoader.resolveStringValue(getMandant(), mandantKonfigurationWerte);
  }

  protected String resolveStringValue(ElectKonfigurationWerte electKonfigurationWerte) {
    return konfigurationExtendedLoader.resolveStringValue(electKonfigurationWerte);
  }

  protected boolean resolveBooleanValue(MandantKonfigurationWerte mandantKonfigurationWerte) {
    return konfigurationExtendedLoader.resolveBooleanValue(getMandant(), mandantKonfigurationWerte);
  }

  protected <V extends Enum< ? >> V resolveEnumValue(MandantKonfigurationWerte mandantKonfigurationWerte, Class<V> enumClass) {
    return konfigurationExtendedLoader.resolveEnumValue(getMandant(), mandantKonfigurationWerte, enumClass);
  }

  public boolean isBtnTestRendered() {
    return principal.hasUseCasePermission(getRequiredPermission());
  }

  public boolean isBtnTestDisabled() {
    return false;
  }

  @Redirect
  public String test() {
    requestUUID = UUID.randomUUID();
    serviceUUID = null;

    String outcome = test(getMandant(), requestUUID);

    resetModel(); // DynaForm-Model neu bauen, um Request-UUID und sonstige Ergebnisdaten anzuzeigen...

    return outcome;
  }

  protected abstract String test(Mandant mandant, UUID requestUUID);

  @Override
  public boolean isBtnSaveRendered() {
    return false;
  }

  @Override
  public String getBtnSaveLabel() {
    return "";
  }

  @Override
  @Redirect
  public String save() {
    return getViewId();
  }

  @Override
  public boolean isBtnResetRendered() {
    return false;
  }

  @Override
  @Redirect
  public String reset() {
    return getViewId();
  }

  @Override
  public boolean isBtnCancelRendered() {
    return false;
  }

  @Override
  @Redirect
  public String cancel() {
    return getViewId();
  }

  protected void addInterfaceExceptionMessage(Throwable cause) {
    addInterfaceExceptionMessage(getLocalizedMessageOrDefault(cause), cause == null ? null : cause.getCause());
  }

  protected void addInterfaceExceptionMessage(String msg, @Nullable Throwable cause) {
    addWarningMessage(Messages.LOCALIZED_MESSAGE_ONLY_MSG_KEY, msg);
    addWarningMessage(Messages.LOCALIZED_MESSAGE_ONLY_MSG_KEY, getRawCausesOrDefault(cause));
  }

  private String getLocalizedMessageOrDefault(Throwable cause) {
    if (cause == null) {
      return "";
    }

    return cause.getLocalizedMessage();
  }

  protected String getRawCausesOrDefault(@Nullable Throwable cause) {
    return addRawCauses(new StringBuilder(), cause).toString();
  }

  private StringBuilder addRawCauses(StringBuilder result, @Nullable Throwable cause) {
    if (cause != null) {
      result.append(cause.toString());

      if (cause.getCause() != null) {
        result.append(System.lineSeparator());

        addRawCauses(result, cause.getCause());
      }
    }

    return result;
  }

  protected void warn(String msg, Throwable cause) {
    LOGGER.warn(msg, cause);
  }

  protected ElectCommonPrincipal getPrincipal() {
    return principal;
  }

  protected Mandant getMandant() {
    return getPrincipal().getMandant();
  }
}
