package com.capgemini.reports.definition.r11report;

import com.capgemini.framework.common.LanguageHelper;
import com.capgemini.framework.common.ReportFolderOutputHelper;
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.pom.status.StatusEnum;
import com.capgemini.framework.teamcenter.object.pom.status.TcEffectivity;
import com.capgemini.framework.teamcenter.object.pom.status.TcReleaseStatus;
import com.capgemini.framework.teamcenter.object.types.SnecmaObjectTypes;
import com.capgemini.reports.bomlineholder.BOMLineHolder;
import com.capgemini.reports.definition.r11report.data.extractor.BomLineBrowserR11;
import com.capgemini.reports.definition.r11report.data.extractor.R11ReceptorRepere;
import com.capgemini.reports.exceptions.FileLoadingException;
import com.capgemini.reports.exceptions.InvalidInputException;
import com.capgemini.reports.exceptions.ReportPrintException;
import com.capgemini.reports.execution.mapconstructor.IMapConstructor;
import com.capgemini.reports.filter.AllIsGoodFilter;
import com.capgemini.reports.printing.PrintParameters;
import com.capgemini.reports.printing.PrintReportHelper;
import com.capgemini.reports.snecmaobjects.ISnecmaObject;
import com.capgemini.reports.snecmaobjects.admin.RFAdminRevision;
import com.capgemini.reports.snecmaobjects.generic.GenericRevision;
import com.capgemini.reports.snecmaobjects.mockup.MockupRevision;
import com.capgemini.reports.snecmaobjects.part.AbstractPart;
import com.capgemini.reports.snecmaobjects.rf.AbstractRF;

import java.util.*;

/**
 * Printer for the report R11. Put in the map all data to send to the template jasper.
 */
public class R11Printer implements IMapConstructor<ExecutionR11, BOMLineHolder> {
    private static final long serialVersionUID = -8731017017029400269L;

    private static final int PERCENT = 100;
    private static final String COMA = ", ";
    private static final String EMPTY = "";
    private static final String NON = "Non";
    private static final String OUI = "Oui";

    private int nbRepereFonctionnelMettreEnMaquette;
    private int nbRepereMisEnMaquette;
    private int nbRepereFonctionnelAvecIncoherence;
    private int nbRepereFonctionnelAvecCoherence;

    @Override
    public void constructDataMaps(final TcSession session, final PrintParameters printParameters, final BOMLineHolder topLine) throws KurtException {
        BomLineBrowserR11 bomLineBrowserR11 = new BomLineBrowserR11();
        bomLineBrowserR11.setFilterNomenclature(new AllIsGoodFilter());
        bomLineBrowserR11.visitTopReceptorBom(session, topLine);
        List<Map<String, ?>> lstMapData = new ArrayList<>();
        Map<R11Keys, Object> parameters = new EnumMap<>(R11Keys.class);
        treatementReceptor(bomLineBrowserR11.getConfig(), lstMapData);
        printParameters.addReportData(lstMapData);
        parameters.put(R11Keys.NOMBRE_REPERE_FONCTIONNEL_METTRE_EN_MAQUETTE, nbRepereFonctionnelMettreEnMaquette);
        parameters.put(R11Keys.NOMBRE_REPERE_FONCTIONNEL_INCOHERENT, nbRepereFonctionnelAvecIncoherence);
        parameters.put(R11Keys.NOMBRE_REPERE_FONCTIONNEL_MAQUETTE, nbRepereMisEnMaquette);
        parameters.put(R11Keys.NOMBRE_REPERE_FONCTIONNEL_MISE_EN_MAQUETTE_COHERENTE, nbRepereFonctionnelAvecCoherence);
        String ratioMiseEnMaquette = safeDiv(nbRepereMisEnMaquette, nbRepereFonctionnelMettreEnMaquette);
        String ratioMaquettesIncoherentes = safeDiv(nbRepereFonctionnelAvecIncoherence, nbRepereMisEnMaquette);
        String ratioMaquettesCoherentes = safeDiv(nbRepereFonctionnelAvecCoherence, nbRepereFonctionnelMettreEnMaquette);
        parameters.put(R11Keys.MISE_EN_MAQUETTE_POURCENTAGE, ratioMiseEnMaquette);
        parameters.put(R11Keys.REPERE_FONCTIONNEL_MAQUETTE_INCOHERENTE_POURCENTAGE, ratioMaquettesIncoherentes);
        parameters.put(R11Keys.POURCENTAGE_MAQUETTE_COHERENTE, ratioMaquettesCoherentes);
        printParameters.addReportParameters(parameters);
    }

    private String safeDiv(final int num, final int denom) {
        if (denom == 0) {
            return "0 %";
        } else {
            return ((PERCENT * num) / denom) + " %";
        }
    }

    private void treatementReceptor(final List<R11ReceptorRepere> lstReceptorRepere, final List<Map<String, ?>> lstMapData) {
        for (R11ReceptorRepere element : lstReceptorRepere) {
            Map<String, String> mapLine = new HashMap<>();
            mapLine.put(R11Keys.IDENTIFIANT_RECEPTEUR.toString(), element.getIDReceptor());
            mapLine.put(R11Keys.NOM_RECEPTEUR.toString(), element.getNameReceptor());
            mapLine.put(R11Keys.REVISION_RECEPTEUR.toString(), element.getRevisionReceptor());
            mapLine.put(R11Keys.REPERE_FONCTIONNEL.toString(), element.getRepereName());
            mapLine.put(R11Keys.REVISION_REPERE_FONCTIONNEL.toString(), element.getRepereRevision());
            mapLine.put(R11Keys.RESPONSABLE_REPERE.toString(), element.getResponsableRepere());
            mapLine.put(R11Keys.MAQUETTE_INTERNE_EXTERNE.toString(), element.getMaquetteInterneExterne());
            extratorDataRepere(element, mapLine);
            lstMapData.add(mapLine);
        }
    }

    private void extratorDataRepere(final R11ReceptorRepere receptorRepere, final Map<String, String> mapLine) {
        BOMLineHolder bomLineRepere = receptorRepere.getRepereFonctionnel();
        if (bomLineRepere.getObjectType().equals(SnecmaObjectTypes.RF_GENERIC_REVISION)) {
            getRepereGeneric(bomLineRepere, mapLine);
        } else {
            getReperePart(bomLineRepere, mapLine);
        }
        defineComponent((AbstractRF) bomLineRepere.getSnecmaObject(), mapLine, bomLineRepere);
    }

    private void getReperePart(final BOMLineHolder bomLineRepere, final Map<String, String> mapLine) {
        StringBuilder iDComponent = new StringBuilder();
        int nbPartBrowsed = 0;
        int nbPart = retrieveNbPart(bomLineRepere.getBomChilds());
        for (BOMLineHolder child : bomLineRepere.getBomChilds()) {
            final ISnecmaObject snecmaObject = child.getSnecmaObject();
            if (snecmaObject.isPart()) {
                nbPartBrowsed++;
                iDComponent.append(snecmaObject.getItemId());
                if (nbPartBrowsed < nbPart) {
                    iDComponent.append(COMA);
                }
                mapLine.put(R11Keys.REVISION_REFERENCE.toString(), snecmaObject.getRevisionId());
                mapLine.put(R11Keys.NOM_REFERENCE.toString(), snecmaObject.getName());
                mapLine.put(R11Keys.DESIGNATION_ANGLAISE.toString(), ((AbstractPart) snecmaObject).getDesignationEN());
                mapLine.put(R11Keys.TYPE_OBJET.toString(), LanguageHelper.getNameTypeWithoutRevision(snecmaObject.getType()));
            }
        }
        mapLine.put(R11Keys.REF_FRABRICANT_REF_SNECMA.toString(), iDComponent.toString());
    }

    private int retrieveNbPart(final List<BOMLineHolder> bomChildMap) {
        int nbPart = 0;
        for (BOMLineHolder bomLineHolder : bomChildMap) {
            if (bomLineHolder.getSnecmaObject().isPart()) {
                nbPart++;
            }
        }
        return nbPart;
    }

    private void getRepereGeneric(final BOMLineHolder bomLineRepere, final Map<String, String> mapLine) {
        final GenericRevision snecmaObject = (GenericRevision) bomLineRepere.getParentBomLine().getSnecmaObject();
        mapLine.put(R11Keys.TYPE_OBJET.toString(), LanguageHelper.getNameTypeWithoutRevision(bomLineRepere.getParentBomLine().getObjectType()));
        mapLine.put(R11Keys.REF_FRABRICANT_REF_SNECMA.toString(), snecmaObject.getItemId());
        mapLine.put(R11Keys.REVISION_REFERENCE.toString(), snecmaObject.getRevisionId());
        mapLine.put(R11Keys.NOM_REFERENCE.toString(), snecmaObject.getName());
        mapLine.put(R11Keys.DESIGNATION_ANGLAISE.toString(), snecmaObject.getDesignationEN());
    }

    private void defineComponent(final AbstractRF rf, final Map<String, String> mapLine, final BOMLineHolder bomLineRepere) {
        boolean isFindDMUStatut = false;
        boolean isFindDataMockUp = false;
        for (TcReleaseStatus status : rf.getStatusList()) {
            if (status.getStatusEnum() == StatusEnum.DMU_READY) {
                isFindDMUStatut = true;
            }
        }
        for (int nbChild = 0; nbChild < bomLineRepere.getBomChilds().size(); nbChild++) {
            if (bomLineRepere.getBomChilds().get(nbChild).getObjectType().equals(SnecmaObjectTypes.RF_ADMIN_REVISION)) {
                RFAdminRevision rfAdmin = (RFAdminRevision) bomLineRepere.getBomChilds().get(nbChild).getSnecmaObject();
                if (LanguageHelper.french(rfAdmin.getEnveloppeCinematique()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getEnveloppeMaintenance()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getEnveloppeMontage()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getGeometriePieceRigide()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getGeometrieSimplifiee()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getTraceAxiale()).equals(OUI)
                        || LanguageHelper.french(rfAdmin.getInterfaceRfAdmin()).equals(OUI)) {
                    isFindDataMockUp = true;
                }
            }
        }
        mapLine.put(R11Keys.STATUT_MISE_EN_MAQUETTE.toString(), isFindDataMockUp && isFindDMUStatut ? OUI : NON);
        mapLine.put(R11Keys.A_METTRE_EN_MAQUETTE.toString(), isFindDataMockUp ? OUI : NON);
        nbRepereFonctionnelMettreEnMaquette = isFindDataMockUp ? nbRepereFonctionnelMettreEnMaquette + 1 : nbRepereFonctionnelMettreEnMaquette;
        nbRepereMisEnMaquette = isFindDataMockUp && isFindDMUStatut ? nbRepereMisEnMaquette + 1 : nbRepereMisEnMaquette;
        MockupRevision mockUpObject = null;
        for (BOMLineHolder bomLineChild : bomLineRepere.getBomChilds()) {
            if (bomLineChild.getObjectType().equals(SnecmaObjectTypes.MOCKUP_REVISION)) {
                mockUpObject = (MockupRevision) bomLineChild.getSnecmaObject();
                mapLine.put(R11Keys.CONTROLE_COHERENCE.toString(), mockUpObject.getCoherenceControl());
            }
        }
        if (mockUpObject == null) {
            mapLine.put(R11Keys.CONTROLE_COHERENCE.toString(), EMPTY);
            mapLine.put(R11Keys.STATUT_PART_C.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_S.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_R.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_M.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_K.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_I.toString(), NON);
            mapLine.put(R11Keys.STATUT_PART_P.toString(), NON);
            nbRepereFonctionnelAvecCoherence =
                    isFindDataMockUp && isFindDMUStatut ? nbRepereFonctionnelAvecCoherence + 1 : nbRepereFonctionnelAvecCoherence;

        } else {
            mapLine.put(R11Keys.CONTROLE_COHERENCE.toString(), mockUpObject.getCoherenceControl());
            boolean isDMUPartK = false;
            boolean isDMUPartP = false;
            boolean isDMUPartS = false;
            boolean isDMUPartR = false;
            boolean isDMUPartC = false;
            boolean isDMUPartI = false;
            boolean isDMUPartM = false;
            for (TcReleaseStatus status : mockUpObject.getStatusList()) {
                isDMUPartC |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_C);
                isDMUPartK |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_K);
                isDMUPartP |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_P);
                isDMUPartI |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_I);
                isDMUPartR |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_R);
                isDMUPartM |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_M);
                isDMUPartS |= defineIsFindStatutMockup(status, StatusEnum.DMU_KO_PART_S);
            }
            mapLine.put(R11Keys.STATUT_PART_C.toString(), isDMUPartC ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_S.toString(), isDMUPartS ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_R.toString(), isDMUPartR ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_M.toString(), isDMUPartM ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_K.toString(), isDMUPartK ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_I.toString(), isDMUPartI ? OUI : NON);
            mapLine.put(R11Keys.STATUT_PART_P.toString(), isDMUPartP ? OUI : NON);

            nbRepereFonctionnelAvecIncoherence = isDMUPartC || isDMUPartI || isDMUPartK || isDMUPartM || isDMUPartP || isDMUPartS || isDMUPartR
                    ? nbRepereFonctionnelAvecIncoherence + 1
                    : nbRepereFonctionnelAvecIncoherence;
            nbRepereFonctionnelAvecCoherence = !isDMUPartC && !isDMUPartI && !isDMUPartK & !isDMUPartM && !isDMUPartP && !isDMUPartS && !isDMUPartR
                    && isFindDataMockUp && isFindDMUStatut ? nbRepereFonctionnelAvecCoherence + 1 : nbRepereFonctionnelAvecCoherence;
        }
    }

    private boolean defineIsFindStatutMockup(final TcReleaseStatus status, final StatusEnum dmuStatus) {
        TcEffectivity effectivity = status.getEffectivity();
        String dateRange = effectivity == null ? null : effectivity.dateRange();
        return (dateRange == null || dateRange.isEmpty()) && status.getStatusEnum() == dmuStatus;
    }

    @Override
    public PrintParameters makeMasterTemplate(final ExecutionR11 report, final BOMLineHolder optionalData)
            throws ReportPrintException, FileLoadingException, InvalidInputException {
        String storageFolder = ReportFolderOutputHelper.getStorageFolderLocation(report.getLaunchType());
        String fileName = report.getFileNameOnDisc();
        return PrintReportHelper.setupPrintParameters(ResourceHelper.getResourceContent(report.getTemplateLocation()), storageFolder, fileName,
                report);
    }
}
