package com.capgemini.reports.definition.r07report.printing;

import com.capgemini.reports.exceptions.FileLoadingException;
import com.capgemini.reports.exceptions.InvalidInputException;
import com.capgemini.reports.templates.Alignment;
import com.capgemini.reports.templates.CellFormat;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Class which allow to build a dynamic template thanks to DynamicTemplateBuilder class.
 */
@Slf4j
@Getter
public class BuilderTemplateR07 {
    private static final int COL_WIDTH_NOM_CN = 125;
    private static final int COL_WIDTH_TYPE_CN = 110;
    private static final int COL_WIDTH_REVISION_CN = 80;
    private static final int COL_WIDTH_ID_CN = 80;
    private static final int COL_WIDTH_NOM_CR = 125;
    private static final int COL_WIDTH_TYPE_CR = 110;
    private static final int COL_WIDTH_REVISION_CR = 100;
    private static final int COL_WIDTH_ID_CR = 100;
    private static final int COL_WIDTH_QUANTITE = 90;
    private static final int COL_WIDTH_PANACHAGE = 80;
    private static final int COL_WIDTH_QUANTITE_CUMULEE = 80;
    private static final int COL_WIDTH_SUIVANT_BESOIN = 80;
    private static final int COL_WIDTH_ALT = 40;
    private static final int COL_WIDTH_LISTE_FOURNISSEUR = 90;
    private static final int COL_WIDTH_SUIVI_DUREE_DE_VIE = 75;
    private static final int COL_WIDTH_SUIVI_UTILISATION = 75;
    private static final int COL_WIDTH_CLASSEMENT = 70;
    private static final int COL_WIDTH_ARTICLE_GESTION = 90;
    private static final int COL_WIDTH_RESPONSABLE_CONCEPTION = 80;
    private static final int COL_WIDTH_REFERENCE_ASSOCIEE = 80;
    private static final int COL_WIDTH_REFERENCE_TRANSPOSEE = 80;
    private static final int COL_WIDTH_REFERENCE_CONCEPTEUR = 140;
    private static final int COL_WIDTH_NOM_REFERENCE = 100;
    private static final int COL_WIDTH_TYPE_REFERENCE = 134;
    private static final int COL_WIDTH_REVISION_REFERENCE = 60;
    private static final int COL_WIDTH_REF_FABRICANT = 90;
    private static final int COL_WIDTH_SUIVI_MONTAGE = 90;
    private static final int COL_WIDTH_RESPONSABLE_REPERE = 80;
    private static final int COL_WIDTH_REVISION_REPERE_FONCTIONNEL = 100;
    private static final int COL_WIDTH_REPERE_FONCTIONNEL = 90;
    private static final int COL_WIDTH_NOM_RECEPTEUR = 140;
    private static final int COL_WIDTH_REVISION_RECEPTEUR = 70;
    private static final int COL_WIDTH_ID_RECEPTEUR = 80;
    private static final int COL_WIDTH_EFFECTIVITY = 170;

    private static final Map<String, Integer> MAP_VALUE_WIDTH_COLUMN = getWidthColumn();
    private static final boolean DYNAMIC_HEADER_EXCEPT_EFFECTIVIY = false;
    private static final boolean STRETCH_OVER_FLOW = true;

    private final List<String> listParam;
    private final Integer numberMaxOfChangeNotice;
    private final List<String> headerColumnName;
    private final String confTitle1;
    private final String confTitle2;
    private final String nameSheetTemplate;

    /**
     * Builds a template for R07 using pre-computed values: number of CNs, etc.
     *
     * @param aListParam a List of differences
     * @param nbMaxCN    the max number of CNs encountered
     * @param conf1name  the name of conf 1
     * @param conf2name  the name of conf 2
     * @param nameSheet  the sheet name
     */
    public BuilderTemplateR07(final List<String> aListParam, final Integer nbMaxCN, final String conf1name, final String conf2name,
                              final String nameSheet) {
        listParam = aListParam;
        numberMaxOfChangeNotice = nbMaxCN;
        headerColumnName = getHeaderWithoutChangeColumn();
        confTitle1 = conf1name;
        confTitle2 = conf2name;
        nameSheetTemplate = nameSheet;
    }

    private static List<String> getHeaderFieldWithoutChangeColumn() {
        List<String> headers = new ArrayList<>();
        headers.add(EnumRecepteurR07.EFFECTIVITE.toString());
        headers.add(EnumRecepteurR07.ID_RECEPTEUR.toString());
        headers.add(EnumRecepteurR07.REVISION_RECEPTEUR.toString());
        headers.add(EnumRecepteurR07.NOM_RECEPTEUR.toString());
        headers.add(EnumRepereR07.REPERE_FONCTIONNEL.toString());
        headers.add(EnumRepereR07.REVISION_REPERE_FONCTIONNEL.toString());
        headers.add(EnumRepereR07.RESPONSABLE_REPERE.toString());
        headers.add(EnumRepereR07.SUIVI_MONTAGE.toString());
        headers.add(EnumComposantR07.REF_FABRICANT.toString());
        headers.add(EnumComposantR07.REVISION_REFERENCE.toString());
        headers.add(EnumComposantR07.TYPE_REFERENCE.toString());
        headers.add(EnumComposantR07.NOM_REFERENCE.toString());
        headers.add(EnumComposantR07.REFERENCE_CONCEPTEUR.toString());
        headers.add(EnumComposantR07.REFERENCE_TRANSPOSEE.toString());
        headers.add(EnumComposantR07.REFERENCE_ASSOCIEE.toString());
        headers.add(EnumComposantR07.RESPONSABLLE_CONCEPTION.toString());
        headers.add(EnumComposantR07.ARTICLE_GESTION.toString());
        headers.add(EnumComposantR07.CLASSEMENT.toString());
        headers.add(EnumComposantR07.SUIVI_UTILISATION.toString());
        headers.add(EnumComposantR07.SUIVI_DUREE_VIE.toString());
        headers.add(EnumComposantR07.LISTE_FOURNISSEUR.toString());
        headers.add(EnumLienNomenclatureR07.ALT.toString());
        headers.add(EnumLienNomenclatureR07.SUIVANT_BESOIN.toString());
        headers.add(EnumLienNomenclatureR07.QUANTITE_CUMULEE.toString());
        headers.add(EnumLienNomenclatureR07.PANACHAGE.toString());
        headers.add(EnumLienNomenclatureR07.QUANTITE.toString());
        headers.add(EnumChangeR07.ID_CR.toString());
        headers.add(EnumChangeR07.REVISION_CR.toString());
        headers.add(EnumChangeR07.TYPE_CR.toString());
        headers.add(EnumChangeR07.NOM_CR.toString());
        return headers;
    }

    private static Map<String, Integer> getWidthColumn() {
        Map<String, Integer> mapWidthColumn = new HashMap<>();
        mapWidthColumn.put(EnumRecepteurR07.EFFECTIVITE.toString(), COL_WIDTH_EFFECTIVITY);
        mapWidthColumn.put(EnumRecepteurR07.ID_RECEPTEUR.toString(), COL_WIDTH_ID_RECEPTEUR);
        mapWidthColumn.put(EnumRecepteurR07.REVISION_RECEPTEUR.toString(), COL_WIDTH_REVISION_RECEPTEUR);
        mapWidthColumn.put(EnumRecepteurR07.NOM_RECEPTEUR.toString(), COL_WIDTH_NOM_RECEPTEUR);
        mapWidthColumn.put(EnumRepereR07.REPERE_FONCTIONNEL.toString(), COL_WIDTH_REPERE_FONCTIONNEL);
        mapWidthColumn.put(EnumRepereR07.REVISION_REPERE_FONCTIONNEL.toString(), COL_WIDTH_REVISION_REPERE_FONCTIONNEL);
        mapWidthColumn.put(EnumRepereR07.RESPONSABLE_REPERE.toString(), COL_WIDTH_RESPONSABLE_REPERE);
        mapWidthColumn.put(EnumRepereR07.SUIVI_MONTAGE.toString(), COL_WIDTH_SUIVI_MONTAGE);
        mapWidthColumn.put(EnumComposantR07.REF_FABRICANT.toString(), COL_WIDTH_REF_FABRICANT);
        mapWidthColumn.put(EnumComposantR07.REVISION_REFERENCE.toString(), COL_WIDTH_REVISION_REFERENCE);
        mapWidthColumn.put(EnumComposantR07.TYPE_REFERENCE.toString(), COL_WIDTH_TYPE_REFERENCE);
        mapWidthColumn.put(EnumComposantR07.NOM_REFERENCE.toString(), COL_WIDTH_NOM_REFERENCE);
        mapWidthColumn.put(EnumComposantR07.REFERENCE_CONCEPTEUR.toString(), COL_WIDTH_REFERENCE_CONCEPTEUR);
        mapWidthColumn.put(EnumComposantR07.REFERENCE_TRANSPOSEE.toString(), COL_WIDTH_REFERENCE_TRANSPOSEE);
        mapWidthColumn.put(EnumComposantR07.REFERENCE_ASSOCIEE.toString(), COL_WIDTH_REFERENCE_ASSOCIEE);
        mapWidthColumn.put(EnumComposantR07.RESPONSABLLE_CONCEPTION.toString(), COL_WIDTH_RESPONSABLE_CONCEPTION);
        mapWidthColumn.put(EnumComposantR07.ARTICLE_GESTION.toString(), COL_WIDTH_ARTICLE_GESTION);
        mapWidthColumn.put(EnumComposantR07.CLASSEMENT.toString(), COL_WIDTH_CLASSEMENT);
        mapWidthColumn.put(EnumComposantR07.SUIVI_UTILISATION.toString(), COL_WIDTH_SUIVI_UTILISATION);
        mapWidthColumn.put(EnumComposantR07.SUIVI_DUREE_VIE.toString(), COL_WIDTH_SUIVI_DUREE_DE_VIE);
        mapWidthColumn.put(EnumComposantR07.LISTE_FOURNISSEUR.toString(), COL_WIDTH_LISTE_FOURNISSEUR);
        mapWidthColumn.put(EnumLienNomenclatureR07.ALT.toString(), COL_WIDTH_ALT);
        mapWidthColumn.put(EnumLienNomenclatureR07.SUIVANT_BESOIN.toString(), COL_WIDTH_SUIVANT_BESOIN);
        mapWidthColumn.put(EnumLienNomenclatureR07.QUANTITE_CUMULEE.toString(), COL_WIDTH_QUANTITE_CUMULEE);
        mapWidthColumn.put(EnumLienNomenclatureR07.PANACHAGE.toString(), COL_WIDTH_PANACHAGE);
        mapWidthColumn.put(EnumLienNomenclatureR07.QUANTITE.toString(), COL_WIDTH_QUANTITE);
        mapWidthColumn.put(EnumChangeR07.ID_CR.toString(), COL_WIDTH_ID_CR);
        mapWidthColumn.put(EnumChangeR07.REVISION_CR.toString(), COL_WIDTH_REVISION_CR);
        mapWidthColumn.put(EnumChangeR07.TYPE_CR.toString(), COL_WIDTH_TYPE_CR);
        mapWidthColumn.put(EnumChangeR07.NOM_CR.toString(), COL_WIDTH_NOM_CR);
        return mapWidthColumn;
    }

    /**
     * Creates the template.
     *
     * @return the template file content (.jrxml)
     * @throws InvalidInputException if a dynamic table could not be created because of invalid grid size (rows/columns)
     * @throws FileLoadingException  if unable to load a template file
     */
    public String createDynamicTemplate() throws InvalidInputException, FileLoadingException {
        List<String> contentCellColumn = createListContentCell();
        List<Integer> lstWidth = createListWidth(finalWidth(), finalTotalHeader());
        String configurationLine = getBackLineConfiguration();
        Map<String, String> mapStyle = defineStyleReport();
        DynamicGridTemplateR07 template = new DynamicGridTemplateR07(lstWidth, contentCellColumn, null, listStretchOverFlow(headerColumnName),
                listParam, configurationLine, mapStyle, nameSheetTemplate);
        template.addHeaderLine(30, headerColumnName, listDynamicHeader(headerColumnName),
                new CellFormat().setAlignment(Alignment.CENTER).setBold(true), null);
        template.ignorePagination();
        return template.generateCode();
    }

    private List<Boolean> listStretchOverFlow(final List<String> lstHeaderFinal) {
        List<Boolean> lstDynamic = new ArrayList<>();
        for (int i = 0; i < lstHeaderFinal.size(); i++) {
            lstDynamic.add(STRETCH_OVER_FLOW);
        }
        return lstDynamic;
    }

    private Map<String, String> defineStyleReport() {
        Map<String, String> mapStyle = new HashMap<>();
        mapStyle.put(EnumRecepteurR07.EFFECTIVITE.toString(), "style_static");
        mapStyle.put(EnumRecepteurR07.ID_RECEPTEUR.toString(), "style_ID_RECEPTEUR");
        mapStyle.put(EnumRecepteurR07.REVISION_RECEPTEUR.toString(), "style_static");
        mapStyle.put(EnumRecepteurR07.NOM_RECEPTEUR.toString(), "style_NOM_RECEPTEUR");
        mapStyle.put(EnumRepereR07.REPERE_FONCTIONNEL.toString(), "style_REPERE_FONCTIONNEL");
        mapStyle.put(EnumRepereR07.REVISION_REPERE_FONCTIONNEL.toString(), "style_static");
        mapStyle.put(EnumRepereR07.RESPONSABLE_REPERE.toString(), "style_RESPONSABLE_REPERE");
        mapStyle.put(EnumRepereR07.SUIVI_MONTAGE.toString(), "style_SUIVI_MONTAGE");
        mapStyle.put(EnumComposantR07.REF_FABRICANT.toString(), "style_REF_FABRICANT");
        mapStyle.put(EnumComposantR07.REVISION_REFERENCE.toString(), "style_static");
        mapStyle.put(EnumComposantR07.TYPE_REFERENCE.toString(), "style_TYPE_REFERENCE");
        mapStyle.put(EnumComposantR07.NOM_REFERENCE.toString(), "style_NOM_REFERENCE");
        mapStyle.put(EnumComposantR07.REFERENCE_CONCEPTEUR.toString(), "style_REFERENCE_CONCEPTEUR");
        mapStyle.put(EnumComposantR07.REFERENCE_TRANSPOSEE.toString(), "style_REFERENCE_TRANSPOSEE");
        mapStyle.put(EnumComposantR07.REFERENCE_ASSOCIEE.toString(), "style_REFERENCE_ASSOCIEE");
        mapStyle.put(EnumComposantR07.RESPONSABLLE_CONCEPTION.toString(), "style_RESPONSABLLE_CONCEPTION");
        mapStyle.put(EnumComposantR07.ARTICLE_GESTION.toString(), "style_ARTICLE_GESTION");
        mapStyle.put(EnumComposantR07.CLASSEMENT.toString(), "style_CLASSEMENT");
        mapStyle.put(EnumComposantR07.SUIVI_UTILISATION.toString(), "style_SUIVI_UTILISATION");
        mapStyle.put(EnumComposantR07.SUIVI_DUREE_VIE.toString(), "style_SUIVI_DUREE_VIE");
        mapStyle.put(EnumComposantR07.LISTE_FOURNISSEUR.toString(), "style_LISTE_FOURNISSEUR");
        mapStyle.put(EnumLienNomenclatureR07.ALT.toString(), "style_ALT");
        mapStyle.put(EnumLienNomenclatureR07.SUIVANT_BESOIN.toString(), "style_SUIVI_BESOIN");
        mapStyle.put(EnumLienNomenclatureR07.QUANTITE_CUMULEE.toString(), "style_QUANTITE_CUMULEE");
        mapStyle.put(EnumLienNomenclatureR07.PANACHAGE.toString(), "style_PANACHAGE");
        mapStyle.put(EnumLienNomenclatureR07.QUANTITE.toString(), "style_QUANTITE");
        mapStyle.put(EnumChangeR07.ID_CR.toString(), "style_static");
        mapStyle.put(EnumChangeR07.REVISION_CR.toString(), "style_static");
        mapStyle.put(EnumChangeR07.TYPE_CR.toString(), "style_static");
        mapStyle.put(EnumChangeR07.NOM_CR.toString(), "style_static");
        for (int i = 0; i < numberMaxOfChangeNotice; i++) {
            mapStyle.put(EnumChangeR07.ID_CN.toString() + "_" + (i + 1), "style_static");
            mapStyle.put(EnumChangeR07.REVISION_CN.toString() + "_" + (i + 1), "style_static");
            mapStyle.put(EnumChangeR07.TYPE_CN.toString() + "_" + (i + 1), "style_static");
            mapStyle.put(EnumChangeR07.NOM_CN.toString() + "_" + (i + 1), "style_static");
        }
        return mapStyle;
    }

    private List<String> createListContentCell() {
        List<String> contentCellColumn = getHeaderFieldWithoutChangeColumn();
        List<String> lstColumnChangeNotice = createColumnFieldChangeNotice();
        for (String aLstColumnChangeNotice : lstColumnChangeNotice) {
            contentCellColumn.add(aLstColumnChangeNotice);
        }
        return contentCellColumn;
    }

    private List<String> createColumnFieldChangeNotice() {
        List<String> lstColumnChangeNotice = new ArrayList<>();
        for (int i = 0; i < numberMaxOfChangeNotice; i++) {
            lstColumnChangeNotice.add(EnumChangeR07.ID_CN.toString() + "_" + (i + 1));
            lstColumnChangeNotice.add(EnumChangeR07.REVISION_CN.toString() + "_" + (i + 1));
            lstColumnChangeNotice.add(EnumChangeR07.TYPE_CN.toString() + "_" + (i + 1));
            lstColumnChangeNotice.add(EnumChangeR07.NOM_CN.toString() + "_" + (i + 1));
        }
        return lstColumnChangeNotice;
    }

    private List<Boolean> listDynamicHeader(final List<String> lstHeaderFinal) {
        List<Boolean> lstDynamic = new ArrayList<>();
        for (int i = 0; i < lstHeaderFinal.size(); i++) {
            lstDynamic.add(DYNAMIC_HEADER_EXCEPT_EFFECTIVIY);
        }
        return lstDynamic;
    }

    private String getBackLineConfiguration() {
        return EnumChangeR07.CONFIGURATION_CONCERNED.toString();
    }

    private List<String> getHeaderWithoutChangeColumn() {
        List<String> lstHeader = new ArrayList<>();
        lstHeader.add("Effectivit&eacute;");
        lstHeader.add("Identifiant r&eacute;cepteur");
        lstHeader.add("R&eacute;vision r&eacute;cepteur");
        lstHeader.add("Nom r&eacute;cepteur");
        lstHeader.add("Rep&egrave;re fonctionnel");
        lstHeader.add("R&eacute;vision rep&egrave;re fonctionnel");
        lstHeader.add("Responsable rep&egrave;re");
        lstHeader.add("Suivi montage");
        lstHeader.add("Ref. Fabricant / Ref. Snecma");
        lstHeader.add("R&eacute;vision r&eacute;f&eacute;rence");
        lstHeader.add("Type r&eacute;f&eacute;rence");
        lstHeader.add("Nom r&eacute;f&eacute;rence");
        lstHeader.add("R&eacute;f&eacute;rence concepteur");
        lstHeader.add("R&eacute;f&eacute;rence transpos&eacute;e");
        lstHeader.add("R&eacute;f&eacute;rence associ&eacute;e");
        lstHeader.add("Responsable conception");
        lstHeader.add("Article de gestion");
        lstHeader.add("Classement");
        lstHeader.add("Suivi utilisation");
        lstHeader.add("Suivi dur&eacute;e de vie");
        lstHeader.add("Liste fournisseur(s) valid&eacute;(s)");
        lstHeader.add("ALT");
        lstHeader.add("SB (Suivant Besoin)");
        lstHeader.add("Quantit&eacute; cumul&eacute;e");
        lstHeader.add("Panachage");
        lstHeader.add("Quantit&eacute;");
        lstHeader.add("Identifiant ChangeRequest");
        lstHeader.add("R&eacute;vision ChangeRequest");
        lstHeader.add("Type ChangeRequest");
        lstHeader.add("Nom ChangeRequest");
        List<String> lstHeadChange = createColumnChangeNotice();
        for (int i = 0; i < numberMaxOfChangeNotice; i++) {
            for (String aLstHeadChange : lstHeadChange) {
                lstHeader.add(aLstHeadChange);
            }
        }
        return lstHeader;
    }

    private List<String> createColumnChangeNotice() {
        List<String> lstColumnChangeNotice = new ArrayList<>();
        lstColumnChangeNotice.add("Identifiant ChangeNotice");
        lstColumnChangeNotice.add("R&eacute;vision ChangeNotice");
        lstColumnChangeNotice.add("Type ChangeNotice");
        lstColumnChangeNotice.add("Nom ChangeNotice");
        return lstColumnChangeNotice;
    }

    private List<String> finalTotalHeader() {
        List<String> lstHeader = getHeaderFieldWithoutChangeColumn();
        List<String> lstColumnChangeNotice = createColumnFieldChangeNotice();
        for (String aLstColumnChangeNotice : lstColumnChangeNotice) {
            lstHeader.add(aLstColumnChangeNotice);
        }
        return lstHeader;
    }

    private Map<String, Integer> finalWidth() {
        Map<String, Integer> mapWidthColumn = MAP_VALUE_WIDTH_COLUMN;
        for (int i = 0; i < numberMaxOfChangeNotice; i++) {
            mapWidthColumn.put(EnumChangeR07.ID_CN.toString() + "_" + (i + 1), COL_WIDTH_ID_CN);
            mapWidthColumn.put(EnumChangeR07.REVISION_CN.toString() + "_" + (i + 1), COL_WIDTH_REVISION_CN);
            mapWidthColumn.put(EnumChangeR07.TYPE_CN.toString() + "_" + (i + 1), COL_WIDTH_TYPE_CN);
            mapWidthColumn.put(EnumChangeR07.NOM_CN.toString() + "_" + (i + 1), COL_WIDTH_NOM_CN);
        }
        return mapWidthColumn;
    }

    private List<Integer> createListWidth(final Map<String, Integer> mapWidth, final List<String> headers) {
        List<Integer> lstWidth = new ArrayList<>();
        for (String header : headers) {
            for (String valKey : mapWidth.keySet()) {
                if (valKey.equals(header)) {
                    lstWidth.add(mapWidth.get(header));
                    break;
                }
            }
        }
        return lstWidth;
    }
}
