package com.capgemini.reports.definition.r10report;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.EmptyNomenclatureException;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.exceptions.NoSuchBomViewException;
import com.capgemini.framework.teamcenter.object.pom.workspace.bom.TcBomObject;
import com.capgemini.framework.teamcenter.object.pom.workspace.bom.TcBomObjectFactory;
import com.capgemini.framework.teamcenter.object.pom.workspace.bom.TcRevisionRule;
import com.capgemini.framework.teamcenter.object.pom.workspace.bom.TcRevisionRuleProperties;
import com.capgemini.framework.teamcenter.object.pom.workspace.bom.product.TcProduct;
import com.capgemini.framework.teamcenter.object.runtime.TcBomWindow;
import com.capgemini.framework.teamcenter.object.runtime.TcBomWindowConfiguration;
import com.capgemini.framework.teamcenter.object.runtime.TcRevisionRulesConfiguration;
import com.capgemini.reports.bomlineholder.BOMLineHolder;
import com.capgemini.reports.bomlineholder.BOMLineHolderFactory;
import com.capgemini.reports.definition.r10report.ExecutionR10.ReportDataR10;
import com.capgemini.reports.exceptions.InvalidInputException;
import com.capgemini.reports.exceptions.InvalidUserInputException;
import com.capgemini.reports.exceptions.MalformedNomenclatureException;
import com.capgemini.reports.exceptions.UserInputErrorEnum;
import com.capgemini.reports.execution.IDataReportPreparator;
import com.capgemini.reports.execution.strategies.IExecutionStrategy;
import com.capgemini.reports.filter.AllIsGoodFilter;
import com.capgemini.reports.filter.FilterExcludeByType;
import com.capgemini.reports.printing.PrintParameters;
import com.capgemini.reports.reports.parameters.EffectivityDate;
import com.capgemini.reports.reports.parameters.MonoMulti;
import com.capgemini.reports.teamcenter.resolution.structureservice.IStructureServiceCaller;
import com.capgemini.reports.teamcenter.resolution.structureservice.MultiStructureServiceCaller;
import com.capgemini.reports.teamcenter.resolution.structureservice.TripleStructureServiceCaller;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.BOMLine;
import com.teamcenter.soa.client.model.strong.Form;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * This class will allow to prepare data and findAll back data for making report R10.
 */
public class DataReportPreparatorR10 implements IDataReportPreparator<ExecutionR10> {
    private static final long serialVersionUID = 9204365823895275478L;
    private static final Logger LOGGER = LoggerFactory.getLogger(DataReportPreparatorR10.class);

    private static final FilterExcludeByType FILTER_MOCKUP_GEOMETRY = new FilterExcludeByType("Mockup Revision", "Geometry Revision"); // Mockup Revision and Geometry Revision can be found in a BOM, but are not needed

    @Override
    public String print(TcSession session, ExecutionR10 execution, IExecutionStrategy executionStrategy) throws KurtException {
        PrintParameters printParameters = prepareData(session, execution);
        executionStrategy.print(printParameters, execution);
        return executionStrategy.getReportFileName(execution) + printParameters.getOuputFileExtension();
    }

    private PrintParameters prepareData(final TcSession session, final ExecutionR10 report) throws KurtException {
        LOGGER.debug("PrepareData started on: {}", report.getReportIdentifier().getReportTitle());

        TcBomObject topLineObject = new TcBomObjectFactory(session, report.getGenerics().getItem(session)).create();
        TcProduct productObject = new TcProduct(session, report.getGenerics().getProductUnit().getProduct(session));
        int unit = report.getGenerics().getProductUnit().getUnit();
        EffectivityDate effectivityDate = report.getEffectivityDate();

        TcRevisionRuleProperties revisionRuleProperties = new TcRevisionRuleProperties(productObject, unit, effectivityDate.isNow() ? null : effectivityDate.getDateTime());

        TcRevisionRule revisionRule = session.findRevRule(report.getRevisionRule());
        TcRevisionRulesConfiguration revRulesConfiguration = new TcRevisionRulesConfiguration(revisionRule, revisionRuleProperties);

        try (TcBomWindow bomWindow = session.createBomWindow(new TcBomWindowConfiguration(topLineObject, revRulesConfiguration))) {
            session.setObjectPropPolicy(report.getFullPolicy());

            // Explode the structure
            BOMLineHolder unbuiltTopLine = explode(session, bomWindow.topLine(), report);

            List<Form> itemRevMaster = unbuiltTopLine.getAllItemRevMasters();
            session.loadProperties(itemRevMaster.toArray(new ModelObject[itemRevMaster.size()]));

            // build the BomLine
            BOMLineHolderFactory.buildTopBom(session, unbuiltTopLine, FILTER_MOCKUP_GEOMETRY);

            // Freeze after processing
            unbuiltTopLine.freeze();
            ReportDataR10 dataR10 = new ReportDataR10(unbuiltTopLine);

            R10Printer printer = new R10Printer(report.getEffectivityDate().isNow() ? null : report.getEffectivityDate().getDateTime());
            PrintParameters printParameters = printer.makeMasterTemplate(report, dataR10);
            printer.constructDataMaps(session, printParameters, dataR10);

            LOGGER.debug("PrepareData ended on: {}", report.getReportIdentifier().getReportTitle());
            return printParameters;
        } catch (EmptyNomenclatureException e) {
            switch (report.getGenerics().getType()) {
                case GENERIC:
                    throw new InvalidUserInputException(UserInputErrorEnum.NO_DATA_COULD_BE_EXTRACTED_FOR_GENERIC_PRODUCT_AND_UNIT, e);
                case GENERIC_ASSEMB:
                    throw new InvalidUserInputException(UserInputErrorEnum.NO_DATA_COULD_BE_EXTRACTED_FOR_GENERIC_ASSEMB_PRODUCT_AND_UNIT, e);
                default:
                    throw new KurtException("The TC Nomenclature Resolution returned null", e);
            }
        }
    }

    private BOMLineHolder explode(final TcSession session, final BOMLine topBomLine, final ExecutionR10 report)
            throws InvalidInputException, MalformedNomenclatureException {
        IStructureServiceCaller service;
        if (MonoMulti.MONO.equals(report.getMonoMulti())) {
            service = new TripleStructureServiceCaller(session);
        } else {
            service = new MultiStructureServiceCaller(session);
        }

        try {
            return service.resolve(topBomLine, new AllIsGoodFilter());
        } catch (EmptyNomenclatureException e) {
            switch (report.getGenerics().getType()) {
                case GENERIC:
                    throw new InvalidUserInputException(UserInputErrorEnum.NO_DATA_COULD_BE_EXTRACTED_FOR_GENERIC_PRODUCT_AND_UNIT, e);
                case GENERIC_ASSEMB:
                    throw new InvalidUserInputException(UserInputErrorEnum.NO_DATA_COULD_BE_EXTRACTED_FOR_GENERIC_ASSEMB_PRODUCT_AND_UNIT, e);
                default:
                    throw new InvalidInputException("The TC Nomenclature Resolution returned null", e);
            }
        } catch (NoSuchBomViewException e) {
            throw new InvalidInputException("No such Bom View", e);
        }
    }
}
