package com.capgemini.reports.bomlineholder.flattener.line;

import com.capgemini.framework.common.StringHelper;
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.bomlineholder.BOMLineHolder;
import com.capgemini.reports.bomlineholder.BOMLineHolderHelper;
import com.capgemini.reports.snecmaobjects.ISnecmaObject;
import com.capgemini.reports.snecmaobjects.admin.RFAdminAPRevision;
import com.capgemini.reports.snecmaobjects.admin.RFAdminARevision;
import com.capgemini.reports.snecmaobjects.admin.RFAdminRevision;
import com.capgemini.reports.snecmaobjects.generic.AbstractGenericRevision;
import com.capgemini.reports.snecmaobjects.part.*;
import com.capgemini.reports.snecmaobjects.product.ProductRevision;
import com.capgemini.reports.snecmaobjects.rf.AbstractRF;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

/**
 * Represents a Receptor/RF receptor/Component/Rf Component.
 *
 * @param <U> a Transformer object producing results of type T
 * @param <T> the result of a transformation by object of type U
 */
@Getter
@Slf4j
public abstract class AbstractQuad<T, U> implements SnecmaLine<T, U> {

    private static final String MSG_NO_RF_ADMIN_A_FOUND = "No RF Admin A Found";
    private static final String MSG_NO_RF_ADMIN_FOUND = "No RF Admin Found";
    private static final String NON = "Non";
    private static final String OUI = "Oui";
    private static final String EMPTY = "";

    private final BOMLineHolder recepteurBL;
    private final BOMLineHolder repereBL;
    private final BOMLineHolder composantBL;
    private final BOMLineHolder repereComposantBL;
    private final int lineNumber;

    private final ISnecmaObject recepteur;
    private final AbstractRF repereRecepteur;
    private final ISnecmaObject composant;
    private final AbstractRF repereComposant;
    protected final TcSession session;

    /**
     * builds a {@link AbstractQuad} object out of its four constituent {@link BOMLineHolder}s.
     *
     * @param session
     * @param recepteurBL       the receptor
     * @param repereRecepteurBL the repere of the receptor
     * @param composantBL       the component
     * @param repereComposantBL the repere of the component
     * @param lineNum           a line number, identifying uniquely and orderly this triplet in the configuration.
     */
    public AbstractQuad(final TcSession session, final BOMLineHolder recepteurBL, final BOMLineHolder repereRecepteurBL, final BOMLineHolder composantBL,
                        final BOMLineHolder repereComposantBL, final int lineNum) {
        this.session = session;
        this.recepteurBL = recepteurBL;
        this.repereBL = repereRecepteurBL;
        this.composantBL = composantBL;
        this.repereComposantBL = repereComposantBL;
        this.lineNumber = lineNum;
        this.recepteur = recepteurBL.getSnecmaObject();
        this.repereRecepteur = (AbstractRF) repereRecepteurBL.getSnecmaObject();
        this.composant = composantBL.getSnecmaObject();
        this.repereComposant = (AbstractRF) repereComposantBL.getSnecmaObject();
    }

    @Override
    public int compareTo(final SnecmaLine<T, U> other) {
        if (this.getClass().isAssignableFrom(other.getClass())) {
            return compareTo((AbstractQuad<T, U>) other);
        } else {
            return getLineId().compareTo(other.getLineId());
        }
    }

    /**
     * Compares this {@link AbstractQuad} to an other one.
     *
     * @param other the other {@link AbstractQuad}
     * @return a difference number. 0 if equal.
     */
    public int compareTo(final AbstractQuad<T, U> other) {
        int cmp = recepteur.getItemId().compareTo(other.recepteur.getItemId());
        if (cmp == 0) {
            cmp = repereRecepteur.getName().compareTo(other.repereRecepteur.getName());
            if (cmp == 0) {
                if (composant == null) {
                    return other.composant == null ? 0 : 1;
                }
                return composant.getItemId().compareTo(other.composant.getItemId());
            }
        }
        return cmp;
    }

    @Override
    public String toString() {
        return "Quad(" + getLineId() + ")";
    }

    @Override
    public String getLineId() {
        return recepteur.getItemId() + "/" + repereRecepteur.getName() + "/" +
                (composant == null ? "null" : composant.getItemId()) + "/" +
                (repereComposant == null ? "null" : repereComposant.getName());
    }

    @Override
    public String getIDReceptor() {
        return recepteur.getItemId();
    }

    @Override
    public String getNameReceptor() {
        return recepteur.getName();
    }

    @Override
    public String getRevisionReceptor() {
        return recepteur.getRevisionId();
    }

    @Override
    public String getRepereName() {
        return repereComposant.getName();
    }

    @Override
    public String getRepereRevision() {
        return repereComposant.getRevisionId();
    }

    @Override
    public String getResponsableRepere() {
        String responsableRepere;
        try {
            if (repereComposant.isRFGeneric()) {
                RFAdminRevision rfAdmin = BOMLineHolderHelper.findRfAdmin(repereComposantBL);
                responsableRepere = rfAdmin.getResponsableRepere();
            } else if (repereComposantBL.getSnecmaObject().isRFPartOrPartAssemb()) {
                if (SnecmaObjectTypes.RF_PART_ASSEMB_REVISION.equals(repereComposantBL.getSnecmaObject().getType())) {
                    RFAdminARevision rfAdminA = BOMLineHolderHelper.findRfAdminA(repereComposantBL);
                    responsableRepere = rfAdminA == null ? MSG_NO_RF_ADMIN_A_FOUND : rfAdminA.getResponsableRepere();
                } else {
                    RFAdminRevision rfAdmin = BOMLineHolderHelper.findRfAdmin(repereComposantBL);
                    responsableRepere = rfAdmin == null ? MSG_NO_RF_ADMIN_FOUND : rfAdmin.getResponsableRepere();
                }
            } else {
                responsableRepere = EMPTY;
            }
            return responsableRepere;
        } catch (KurtException e) {
            log.warn("Unable to find the correct RF Admins below Rf: " + repereComposantBL.getSnecmaObject().getName(), e);
            return EMPTY;
        }
    }

    @Override
    public String getSuiviMontage() {
        String suiviMontage;
        if (repereComposant.isRFGeneric()) {
            suiviMontage = NON;
        } else if (repereComposantBL.getSnecmaObject().isRFPartOrPartAssemb()) {
            try {
                if (SnecmaObjectTypes.RF_PART_ASSEMB_REVISION.equals(repereComposantBL.getSnecmaObject().getType())) {
                    RFAdminARevision rfAdminA = BOMLineHolderHelper.findRfAdminA(repereComposantBL);
                    suiviMontage = rfAdminA == null ? MSG_NO_RF_ADMIN_A_FOUND : rfAdminA.getSuiviMontage();
                } else {
                    RFAdminAPRevision rfAdminAP = BOMLineHolderHelper.findRfAdminAP(repereComposantBL);
                    suiviMontage = rfAdminAP == null ? MSG_NO_RF_ADMIN_FOUND : rfAdminAP.getSuiviMontage();
                }
            } catch (KurtException e) {
                log.warn("Unable to find the correct RF Admin A/AP below RF Part / RF PArt Assemb: " + repereComposantBL.getSnecmaObject().getName(),
                        e);
                return EMPTY;
            }
        } else {
            suiviMontage = EMPTY;
        }
        return suiviMontage;
    }

    @Override
    public String getIDComponent() {
        return composant.getItemId();
    }

    @Override
    public String getIDRevisionComponent() {
        return composant.getRevisionId();
    }

    @Override
    public String getTypeReference() {
        String typeReference;
        if (composant.isPart()) {
            typeReference = PartTypeExtractorHelper.extractType(composant);
        } else if (composant.isGeneric()) {
            String type = composant.getType();
            if (SnecmaObjectTypes.GENERIC_REVISION.equals(type)) {
                typeReference = "Générique";
            } else if (SnecmaObjectTypes.GENERIC_ASSEMB_REVISION.equals(type)) {
                typeReference = "Générique Montage";
            } else {
                typeReference = EMPTY;
            }
        } else {
            typeReference = EMPTY;
        }
        return typeReference;
    }

    @Override
    public String getNameReference() {
        return composant.getName();
    }

    @Override
    public String getReferenceConceptor() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getRefCompleteConcepteur();
        } else {
            return EMPTY;
        }
    }

    @Override
    public String getReferenceTransposed() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getRefTransposeeSnecma();
        } else {
            return EMPTY;
        }
    }

    @Override
    public String getReferenceAssociated() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getRefAssociee();
        } else {
            return EMPTY;
        }
    }

    @Override
    public String getResponsableConception() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getResponsableConception();
        } else if (composant.isGeneric()) {
            return ((AbstractGenericRevision) composant).getResponsableConception();
        } else {
            return EMPTY;
        }
    }

    @Override
    public String getArticleGestion() {
        if (SnecmaObjectTypes.isAltOrDet(composant.getType()) || SnecmaObjectTypes.PART_ASSEMB_REVISION.equals(composant.getType())) {
            return OUI;
        }
        return EMPTY;
    }

    @Override
    public String getClassement() {
        if (composant.isPart()) {
            if (SnecmaObjectTypes.PART_MAT_REVISION.equals(composant.getType())) {
                return ((PartMatRevision) composant).getClassementMat();
            } else {
                return ((AbstractPart) composant).getClassement();
            }
        } else {
            return EMPTY;
        }
    }

    @Override
    public String getSuiviUtilisation() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getSuiviUtilisation();
        } else {
            return OUI;
        }
    }

    @Override
    public String getSuiviDureeVie() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getSuiviDureeVie();
        } else {
            return NON;
        }
    }

    @Override
    public String[] getSuppliersList() {
        String[] lst;
        if (composant.isPart() && !SnecmaObjectTypes.PART_NO_AERO_REVISION.equals(composant.getType())) {
            if (SnecmaObjectTypes.PART_AERO_REVISION.equals(composant.getType())) {
                lst = ((PartAeroRevision) composant).getLstFournisseurs();
            } else if (SnecmaObjectTypes.PART_MAT_REVISION.equals(composant.getType())) {
                lst = ((PartMatRevision) composant).getLstFournisseurs();
            } else if (SnecmaObjectTypes.STANDARD_REVISION.equals(composant.getType())) {
                lst = ((StandardRevision) composant).getLstFournisseurs();
            } else if (SnecmaObjectTypes.DET_REVISION.equals(composant.getType())) {
                lst = ((DETRevision) composant).getLstFournisseurs();
            } else if (SnecmaObjectTypes.ALTERNATE_REVISION.equals(composant.getType())) {
                lst = ((AlternateRevision) composant).getLstFournisseurs();
            } else {
                lst = new String[0];
            }
        } else {
            lst = new String[0];
        }
        return lst;
    }

    @Override
    public String getALT() {
        return composantBL.getBomAlt();
    }

    @Override
    public String getSB() {
        return composantBL.getBomSb();
    }

    @Override
    public String getQuantiteCumulee() {
        return composantBL.getBomQtyCumul();
    }

    @Override
    public String getPanachage() {
        return composantBL.getBomPanache();
    }

    @Override
    public String getQuantite() {
        return composantBL.getBomQty();
    }

    @Override
    public String getMaquetteInterneExterne() {
        return EMPTY;
    }

    @Override
    public Double getMass() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getMass();
        } else {
            return null;
        }
    }

    @Override
    public String getMassUnit() {
        if (composant.isPart()) {
            return ((AbstractPart) composant).getMassUnit();
        } else {
            return StringHelper.EMPTY;
        }
    }

    @Override
    public String getDesignationENG() {
        String designation;
        if (composant.isPart()) {
            designation = ((AbstractPart) composant).getDesignationEN();
        } else if (composant.isGeneric()) {
            designation = ((AbstractGenericRevision) composant).getDesignationEN();
        } else if (composant.isProduct()) {
            designation = ((ProductRevision) composant).getDesignationEN();
        } else {
            designation = StringHelper.EMPTY;
        }
        return designation;
    }

}
