package com.capgemini.reports.definition.r26report;

import com.capgemini.framework.common.ResourceHelper;
import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.object.types.SnecmaObjectTypes;
import com.capgemini.reports.JasperTemplate;
import com.capgemini.reports.definition.r26report.ExecutionR26.ReportDataR26;
import com.capgemini.reports.execution.mapconstructor.AbstractStaticTemplateMapConstructor;
import com.capgemini.reports.execution.mapconstructor.IMapConstructor;
import com.capgemini.reports.printing.PrintParameters;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Extracts the relevant data obtained from TC into the expected List of Maps for Jasper.
 */
@Slf4j
public class R26Printer extends AbstractStaticTemplateMapConstructor<ExecutionR26, ReportDataR26> implements IMapConstructor<ExecutionR26, ReportDataR26> {

  private static final long serialVersionUID = 4281716591716247163L;

  private static final String SUBREPORT_P1 = "SUBREPORT_P1";
  private static final String SUBREPORT_P2 = "SUBREPORT_P2";
  private static final String MESSAGE_PRODUIT_NON_CONSOMME = "Les produits notés en rouge ne consomment pas le composant de la ligne de nomenclature";
  private static final String MESSAGE_PRODUIT_COMPOSANT_STANDARD = "Pour le composant de type standard, il n'est pas vérifié que les produits en violet consomment le composant.";
  private static final String MESSAGE_AUCUNE_DONNEE = "Aucune donnée n’a pu être extraite, aucune ligne de nomenclature trouvée pour le composant";
  private static final String MESSAGE_AUCUNE_DONNEE_ETUDE = "Aucune donnée Etude n’a pu être extraite, aucune ligne de nomenclature trouvée pour le composant";
  private static final String MESSAGE_AUCUNE_DONNEE_MONTAGE = "Aucune donnée Montage n’a pu être extraite, aucune ligne de nomenclature trouvée pour le composant";

  /**
   * Puts the data gathered by an {@link ExecutionR26} into some {@link PrintParameters} for printing.
   *
   * @param reportData the data-bearing {@link ReportDataR26}
   * @param mainReport the {@link PrintParameters}
   */
  private void print(final ReportDataR26 reportData, final PrintParameters mainReport) throws KurtException {

    boolean vueEtudeEmpty = setupPage1(reportData, mainReport);
    boolean vueMontageEmpty = setupPage2(reportData, mainReport);

    Map<R26Keys, String> map = new EnumMap<>(R26Keys.class);
    if (vueEtudeEmpty && vueMontageEmpty) {
      map.put(R26Keys.MESSAGE_1, MESSAGE_AUCUNE_DONNEE);
    }
    else {
      map.put(R26Keys.MESSAGE_1, vueEtudeEmpty ? MESSAGE_AUCUNE_DONNEE_ETUDE : MESSAGE_PRODUIT_NON_CONSOMME);
      map.put(R26Keys.MESSAGE_2, vueMontageEmpty ? MESSAGE_AUCUNE_DONNEE_MONTAGE : MESSAGE_PRODUIT_NON_CONSOMME);
      map.put(R26Keys.MESSAGE_3, vueEtudeEmpty ? "" : MESSAGE_PRODUIT_COMPOSANT_STANDARD);
      map.put(R26Keys.MESSAGE_4, vueMontageEmpty ? "" : MESSAGE_PRODUIT_COMPOSANT_STANDARD);
    }
    List<Map<R26Keys, ?>> test = new ArrayList<>();
    test.add(map);
    mainReport.addReportDataFromEnum(test);

    // Setup main report
    mainReport.addReportData(setupEmptyData());
  }

  private static List<Map<String, ?>> setupEmptyData() {
    List<Map<String, ?>> list = new ArrayList<>();
    list.add(new HashMap<String, Object>());
    return list;
  }

  private static boolean setupPage1(final ReportDataR26 reportData, final PrintParameters mainReport)
    throws KurtException {
    boolean emptySubReport = true;
    try (InputStream page1Stream = ResourceHelper.getResourceAsStream(JasperTemplate.TEMPLATE_R26_SUBREPORT.getFilepath())) {
      List<Map<R26Keys, ?>> vueEtudeList = setupPage1Data(reportData);

      if (!vueEtudeList.isEmpty()) {
        emptySubReport = false;
      }

      mainReport.addSubReport(SUBREPORT_P1, page1Stream, vueEtudeList, new EnumMap<>(R26Keys.class));
    }
    catch (IOException e) {
      log.error("Unable to close template of the R26 report", e);
    }
    return emptySubReport;
  }

  private static boolean setupPage2(final ReportDataR26 reportData, final PrintParameters mainReport)
    throws KurtException {
    boolean emptySubReport = true;
    try (InputStream page2Stream = ResourceHelper.getResourceAsStream(JasperTemplate.TEMPLATE_R26_SUBREPORT.getFilepath())) {
      List<Map<R26Keys, ?>> vueMontageList = setupPage2Data(reportData);

      if (!vueMontageList.isEmpty()) {
        emptySubReport = false;
      }

      mainReport.addSubReport(SUBREPORT_P2, page2Stream, vueMontageList, new EnumMap<>(R26Keys.class));
    }
    catch (IOException e) {
      log.error("Unable to close template of the R26 report", e);
    }
    return emptySubReport;
  }

  private static List<Map<R26Keys, ?>> setupPage1Data(ReportDataR26 reportData) {
    List<Map<R26Keys, ?>> vueEtudeList = new ArrayList<>();
    for (R26BomLine currentLine : reportData.getR26BomLines()) {
      if (currentLine.getModule() == null || currentLine.getModule().getTypeObject().getName().equals(SnecmaObjectTypes.GENERIC_REVISION)) {
        Map<R26Keys, String> map = getR26KeysStringMap(currentLine, reportData.isStandard());
        vueEtudeList.add(map);
      }
    }
    return vueEtudeList;
  }

  private static List<Map<R26Keys, ?>> setupPage2Data(ReportDataR26 reportData) {
    List<Map<R26Keys, ?>> vueMontageList = new ArrayList<>();
    for (R26BomLine currentLine : reportData.getR26BomLines()) {
      if (currentLine.getModule() != null && currentLine.getModule().getTypeObject().getName().equals(SnecmaObjectTypes.GENERIC_ASSEMB_REVISION)) {
        Map<R26Keys, String> map = getR26KeysStringMap(currentLine, reportData.isStandard());
        vueMontageList.add(map);
      }
    }
    return vueMontageList;
  }

  private static Map<R26Keys, String> getR26KeysStringMap(R26BomLine currentLine, boolean isStandard) {
    Map<R26Keys, String> map = new EnumMap<>(R26Keys.class);

    map.put(R26Keys.RECEPTOR_ID, currentLine.getReceptor() == null ? "" : currentLine.getReceptor().get_item_id());
    map.put(R26Keys.RECEPTOR_REVISION, currentLine.getReceptor() == null ? "" : currentLine.getReceptor().get_item_revision_id());
    map.put(R26Keys.RECEPTOR_NAME, currentLine.getReceptor() == null ? "" : currentLine.getReceptor().get_object_name());

    map.put(R26Keys.REPERE_ID, currentLine.getRf() == null ? "" : currentLine.getRf().get_item_id());
    map.put(R26Keys.REPERE_REVISION, currentLine.getRf() == null ? "" : currentLine.getRf().get_item_revision_id());
    map.put(R26Keys.REPERE_NAME, currentLine.getRf() == null ? "" : currentLine.getRf().get_object_name());

    map.put(R26Keys.QUANTITY, currentLine.getQuantity());
    map.put(R26Keys.UNIT_OF_MEASURE, currentLine.getUnitOfMeasure());

    map.put(R26Keys.PRODUCT, currentLine.getProductRev() == null ? "" : currentLine.getProductRev().getItemId());
    map.put(R26Keys.PRODUCT_LINE, currentLine.getProductRev() == null ? "" : currentLine.getProductRev().getProductLine());
    map.put(R26Keys.EFFECTIVITY_UNIT, currentLine.getEffectivity() == null ? "" : currentLine.getEffectivity());

    map.put(R26Keys.MODULE_ID, currentLine.getModule() == null ? "" : currentLine.getModule().get_item_id());
    map.put(R26Keys.MODULE_NAME, currentLine.getModule() == null ? "" : currentLine.getModule().get_object_name());

    map.put(R26Keys.CONSUMED_BY_PRODUCT, String.valueOf(currentLine.getConsumedByProduct()));
    map.put(R26Keys.TYPE_STANDARD, String.valueOf(isStandard));
    return map;
  }

  @Override
  public void constructDataMaps(final TcSession session, final PrintParameters printParameters, final ReportDataR26 reportData) throws KurtException {
    long start = System.currentTimeMillis();
    print(reportData, printParameters);
    log.trace("Execution time : {} ms for {}", System.currentTimeMillis() - start, "data filtering");

    log.info("Browsing the Snecma Objects");
  }
}
