
package de.ivu.elect.business.system.control;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import javax.ejb.Asynchronous;
import javax.ejb.Stateless;
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.mandant.boundary.MandantDAO;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.business.system.boundary.SystemUebersicht;
import de.ivu.elect.business.system.entity.SystemCheckStatus;
import de.ivu.elect.business.system.entity.SystemLogQuelle;
import de.ivu.elect.jee.faces.DevelopmentStore;
import de.ivu.elect.jee.presentation.status.StatusEntry;
import de.ivu.elect.jee.presentation.status.StatusOption;
import de.ivu.elect.jee.presentation.status.StatusOptionGroup;

/**
 * ELECT-5970
 */
@Stateless
public class SystemStatusCheckPostStartupAsync {

  private static final Logger LOG = LoggerFactory.getLogger(SystemStatusCheckPostStartupAsync.class);

  @Inject
  private transient SystemUebersicht systemUebersicht;

  @Inject
  private transient KonfigurationExtendedLoader konfigurationExtendedLoader;

  @Inject
  private transient SystemLogWriter systemLogWriter;

  @Inject
  private transient MandantDAO mandantDAO;

  @Inject
  private transient SystemId systemId;

  @Asynchronous // ELECT-5970
  public void postStartupAsync() {

    dumpSystemId();

    LOG.info("******************************************************");
    LOG.info("************** System Check **************************");
    LOG.info("******************************************************");

    if (DevelopmentStore.isDevelopmentStage()) {
      LOG.info("******************************************************");
      LOG.info("***** System Check nicht ausgeführt (Development) ****");
      LOG.info("******************************************************");
      return;
    }

    try {
      SystemCheckStatus systemCheckStatus = bestimmeSystemCheckStatus();

      if (systemCheckStatus.isDeaktiviert()) {
        LOG.info("******************************************************");
        LOG.info("***** System Check nicht ausgeführt (Deaktiviert) ****");
        LOG.info("******************************************************");
        return;
      }
    } catch (Exception e) {
      LOG.warn("Fehler beim Ermitteln des System Check Status", e);
    }

    LOG.info("Warte auf System Check");
    try {
      TimeUnit.SECONDS.sleep(20); // Warten, bis alles fertig...workaround...20 Sekunden => ELECTMUC-1898
    } catch (InterruptedException e) {
      throw new RuntimeException(e.getMessage(), e);
    }

    AtomicLong anzahlFehler = new AtomicLong(0L);
    AtomicLong anzahlWarnungen = new AtomicLong(0L);
    AtomicLong anzahlOk = new AtomicLong(0L);

    for (Mandant mandant : mandantDAO.findByAll()) {
      checkMandant(anzahlFehler, anzahlWarnungen, anzahlOk, mandant);
    }

    LOG.info("*****************************************************************************************************");
    LOG.info("********* System Check - done, OK: " + anzahlOk + ", WARN: " + anzahlWarnungen + ", ERROR: " + anzahlFehler);
    LOG.info("*****************************************************************************************************");
  }

  private void dumpSystemId() {
    try {
      systemId.setSystemId(konfigurationExtendedLoader.resolveStringValue(ElectKonfigurationWerte.SYSTEM_ID));
      LOG.info("**************************************************************************************");
      LOG.info("************** System: " + systemId.getSystemId() + " **************************");
      LOG.info("**************************************************************************************");
      LOG.info("");
      LOG.info("");
    } catch (Exception e) {
      // ignore
      systemId.setSystemId("<->");
    }
  }

  @Asynchronous
  public void checkMandant(Mandant mandant) {
    LOG.info("Check Mandant: " + mandant.getNummer());
    AtomicLong anzahlFehler = new AtomicLong();
    AtomicLong anzahlWarnungen = new AtomicLong();
    AtomicLong anzahlOk = new AtomicLong();
    checkMandant(anzahlFehler, anzahlWarnungen, anzahlOk, mandant);
    LOG.info(
        "Check Mandant done: " + mandant.getNummer() + ", anzahlFehler = [" + anzahlFehler + "], anzahlWarnungen = [" + anzahlWarnungen + "], anzahlOk = [" + anzahlOk + "]");
  }

  private void checkMandant(AtomicLong anzahlFehler, AtomicLong anzahlWarnungen, AtomicLong anzahlOk, Mandant mandant) {
    LOG.info("Check Mandant: " + mandant);
    for (StatusOptionGroup statusOptionGroup : systemUebersicht.getStatusOptionGroups(mandant)) {
      String gruppe = statusOptionGroup.getHeader();
      LOG.info("Check Mandant: " + mandant + ", gruppe=" + gruppe);
      for (StatusOption statusOption : statusOptionGroup.getStatusOptions()) {
        StatusEntry status = systemUebersicht.ermittleStatus(statusOption);
        if (status.isSuccess()) {
          anzahlOk.incrementAndGet();
          LOG.info("System Check OK, Mandant: " + mandant.getNummer() + ", " + gruppe + " - " + status.getLabel());
          if (statusOption.getType().isLogInfo()) {
            systemLogWriter.writeInfoLogMessageFuerMandant(mandant, "System Check " + gruppe + " - " + status.getLabel(), SystemLogQuelle.SYSTEM);
          }
        } else if (status.isWarn()) {
          anzahlWarnungen.incrementAndGet();
          LOG.warn("System Check WARN, Mandant: " + mandant.getNummer() + ", " + gruppe + " - " + status.getLabel());
          if (statusOption.getType().isLogWarning()) {
            systemLogWriter.writeWarnLogMessageFuerMandant(mandant, "System Check " + gruppe + " - " + status.getLabel(), SystemLogQuelle.SYSTEM);
          }
        } else if (status.isError()) {
          anzahlFehler.incrementAndGet();
          LOG.error("System Check ERROR, Mandant: " + mandant.getNummer() + ", " + gruppe + " - " + status.getLabel());
          if (statusOption.getType().isLogError()) {
            systemLogWriter.writeErrorLogMessageFuerMandant(mandant, "System Check " + gruppe + " - " + status.getLabel(), SystemLogQuelle.SYSTEM);
          }
        }
      }
    }
  }

  protected SystemCheckStatus bestimmeSystemCheckStatus() {
    return konfigurationExtendedLoader.resolveEnumValue(ElectKonfigurationWerte.ELECT_COMMON_SYSTEM_CHECK_STATUS_AFTER_STARTUP, SystemCheckStatus.class);
  }
}
