package com.capgemini.reports.logging;

import com.capgemini.framework.common.StringHelper;
import com.capgemini.framework.common.TeamcenterDateFormatter;
import com.capgemini.reports.database.HibernateUtil;
import com.capgemini.reports.database.javabean.DbReport;
import com.capgemini.reports.database.javabean.DbSchedulingReport;
import com.capgemini.reports.database.javabean.DbUser;
import com.capgemini.reports.database.manager.MngCriteriaVal;
import com.capgemini.reports.database.manager.MngReport;
import com.capgemini.reports.database.manager.MngSchedulingCriteriaVal;
import com.capgemini.reports.exceptions.NotFoundException;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.google.common.base.Joiner;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import java.text.SimpleDateFormat;

/**
 * This class will provide all methods which will allow to log every step of the report's execution.
 */
@Slf4j
public final class ReportLoggerHelper {
  private static final String TITLE_REPORT = "Rapport ";

  private static final String ENTRY_ERROR_MESSAGE = " - Message d'erreur: ";
  private static final String ENTRY_WITH_CRITERIA = " - Avec les critères suivants:";
  private static final String ENTRY_BY_USER = " - par l'utilisateur '";
  private static final String ENTRY_UID = " - UID=";
  private static final String ENTRY_FINISHED = " - terminé le ";
  private static final String ENTRY_STARTED = " - Démarré le ";
  private static final String ENTRY_DASH = " - ";
  private static final String ENTRY_STATUS = " - TcReleaseStatus=";

  private static final String STATUS_AUTOMATIC = " par workflow";
  private static final String STATUS_DELAYED = " en différé";
  private static final String STATUS_SCHEDULING_LAUNCHED = " programmé par planification et actuellement lancé ";
  private static final String STATUS_SCHEDULED = " planifié";
  private static final String MSG_NO_REPORT_FOUND_WITH_THIS_ID = " (No report found with this ID)";

  private ReportLoggerHelper() {

  }

  /**
   * To log the beginning of the report's execution.
   *
   * @param aTheExecutingReport      will provide the informations of the report on the database
   * @param aAbstractExecutionReport will provide the informations of the report's execution
   */
  public static void logStart(final DbReport aTheExecutingReport, final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    StringBuilder logMsg = new StringBuilder("Début de l'exécution du rapport ")
      .append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName());
    logMsg.append(ENTRY_UID).append(getSafeUID(aTheExecutingReport));
    logMsg.append(ENTRY_STARTED).append(aAbstractExecutionReport.getStartTime());
    EventsLogger.log(logMsg.toString());

  }

  private static String getSafeUID(final DbReport aTheExecutingReport) {
    if (aTheExecutingReport == null || aTheExecutingReport.getReportUid() == null) {
      return MSG_NO_REPORT_FOUND_WITH_THIS_ID;
    }
    else {
      return aTheExecutingReport.getReportUid();
    }
  }

  /**
   * Logs the fact that a report's exectution reached completion, in a specific file (the file is specified by the log appender in the logging properties of JBoss).
   *
   * @param theExecutingReport       the report being executed, as written in the database.
   * @param fileNameWithExtension    the file location of the generated report.
   * @param aAbstractExecutionReport will provide the informations of the report
   */
  public static void logCompletion(final DbReport theExecutingReport, final String fileNameWithExtension,
                                   final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    StringBuilder logMsg = new StringBuilder(TITLE_REPORT).append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName())
      .append(" terminé avec succès");
    logMsg.append(ENTRY_UID).append(getSafeUID(theExecutingReport));
    logMsg.append(ENTRY_STARTED).append(aAbstractExecutionReport.getStartTime());
    logMsg.append(ENTRY_FINISHED).append(aAbstractExecutionReport.getEndTime());
    logMsg.append(ENTRY_STATUS).append(theExecutingReport == null ? MSG_NO_REPORT_FOUND_WITH_THIS_ID : theExecutingReport.getState());
    logMsg.append(" - Fichier généré : ").append(fileNameWithExtension);
    EventsLogger.log(logMsg.toString());
  }

  /**
   * Log the provided error and message in a specific file (the file is specified by the log appender in the logginig properties of JBoss).
   *
   * @param msg                      An error Message
   * @param error                    the actual error that caused this log
   * @param aAbstractExecutionReport will provide the informations of the report
   */
  public static void logError(final String msg, final Throwable error, final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    DbReport theExecutingReport = null;
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.openSession();
    try {
      theExecutingReport = new MngReport().searchByUid(aAbstractExecutionReport.getReportTechnicalUid(), session);
    }
    catch (NotFoundException e) {
      log.error("Unable to find a report in DB, can't log", e);
    }
    finally {
      session.close();
    }
    String status;
    if (theExecutingReport != null) {
      status = theExecutingReport.getState();
    }
    else {
      status = MSG_NO_REPORT_FOUND_WITH_THIS_ID;
    }

    StringBuilder logMsg =
      new StringBuilder(TITLE_REPORT).append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName()).append(" en échec");
    logMsg.append(ENTRY_UID).append(aAbstractExecutionReport.getReportTechnicalUid());
    logMsg.append(ENTRY_STARTED).append(aAbstractExecutionReport.getStartTime());
    logMsg.append(ENTRY_FINISHED).append(aAbstractExecutionReport.getFailureTime());
    logMsg.append(ENTRY_STATUS).append(status);
    logMsg.append(ENTRY_ERROR_MESSAGE).append(msg);
    EventsLogger.log(logMsg.toString(), error);
  }

  /**
   * Logs the fact that a report was requested by a user, in a specific file (the file is specified by the log appender in the logginig properties of JBoss).
   */
  public static void logRequest(final DbUser requestingUser, final DbReport theExecutingReport, final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    StringBuilder logMsg =
      new StringBuilder(TITLE_REPORT).append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName()).append(" lancé");

    // Specially for delayed reports
    switch (aAbstractExecutionReport.getLaunchType()) {
      case AUTOMATIC:
        logMsg.append(STATUS_AUTOMATIC);
        break;
      case DELAYED:
        logMsg.append(STATUS_DELAYED);
        break;
      default:
        break;
    }

    logMsg.append(ENTRY_UID).append(getSafeUID(theExecutingReport));
    logMsg.append(ENTRY_BY_USER).append(requestingUser.getLogin()).append('\'');
    logMsg.append(ENTRY_WITH_CRITERIA);
    logMsg.append(StringHelper.implodeList(ENTRY_DASH, new MngCriteriaVal().searchCriteriasByReportUID(theExecutingReport.getReportUid())));
    logMsg.append(ENTRY_STARTED).append(aAbstractExecutionReport.getPostingTime());
    EventsLogger.log(logMsg.toString());
  }

  /**
   * Logs the fact that a scheduling was requested by a user, in a specific file (the file is specified by the log appender in the logginig properties of JBoss).<br>
   */
  public static void logSchedulingRequestWaiting(Session session, final DbUser requestingUser, final DbSchedulingReport theExecutingReport,
                                                 final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    StringBuilder logMsg = new StringBuilder(TITLE_REPORT).append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName())
      .append(STATUS_SCHEDULED);
    logMsg.append(ENTRY_BY_USER).append(requestingUser.getLogin()).append('\'');
    logMsg.append(ENTRY_WITH_CRITERIA);
    logMsg.append(Joiner.on(ENTRY_DASH).join(new MngSchedulingCriteriaVal().searchCriteria(session, theExecutingReport.getId())));
    logMsg.append(" - Planifié le ").append(new SimpleDateFormat(TeamcenterDateFormatter.DD_MM_YYYY).format(theExecutingReport.getLastUpdate()));
    EventsLogger.log(logMsg.toString());
  }


  /**
   * Logs the fact that a scheduled report was posted, in a specific file (the file is specified by the log appender in the logginig properties of JBoss).
   */
  public static void logSchedulingRequest(final DbReport theExecutingReport, final AbstractExecutionReport<?, ?> aAbstractExecutionReport) {
    StringBuilder logMsg = new StringBuilder(TITLE_REPORT).append(aAbstractExecutionReport.getReportIdentifier().buildCompleteReportName())
      .append(STATUS_SCHEDULING_LAUNCHED);
    logMsg.append(ENTRY_WITH_CRITERIA);
    logMsg.append(StringHelper.implodeList(ENTRY_DASH, new MngCriteriaVal().searchCriteriasByReportUID(theExecutingReport.getReportUid())));
    logMsg.append(ENTRY_STARTED).append(aAbstractExecutionReport.getPostingTime());
    EventsLogger.log(logMsg.toString());
  }
}
