package com.capgemini.reports.reports.parameters.checker;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.queries.saved.modelobject.ItemRevisionQuery;
import com.capgemini.reports.changeobjects.UnitRevision;
import com.capgemini.reports.exceptions.InvalidUserInputException;
import com.capgemini.reports.exceptions.UserInputErrorEnum;
import com.capgemini.reports.reports.parameters.IChecker;
import com.capgemini.reports.reports.parameters.ProductUnit;
import com.capgemini.reports.snecmaobjects.generic.AbstractGenericRevision;
import com.capgemini.reports.teamcenter.ObjectInfoHelper;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

import static com.capgemini.framework.teamcenter.object.SnecmaObjectProperties.PV_UNIT;

/**
 * This class checks if a a given Product-Unit-Generic is valid.
 */
@Slf4j
public class ProductUnitGenericChecker implements IChecker {

    private final String genericId;
    private final ProductUnit productUnit;

    /**
     * Constructor.
     *
     * @param genericId   String - the generic Id
     * @param productUnit {@link ProductUnit}
     */
    public ProductUnitGenericChecker(final String genericId, final ProductUnit productUnit) {
        this.genericId = genericId;
        this.productUnit = productUnit;
    }

    private static List<ItemRevision> transformArray(final ModelObject[] objects) {
        List<ItemRevision> newList = new ArrayList<>();
        for (ModelObject object : objects) {
            newList.add((ItemRevision) object);
        }
        return newList;
    }

    @Override
    public void check(final TcSession session) throws InvalidUserInputException {
        productUnit.parseUserUnit();

        // Find the product
        List<ItemRevision> productRevisions = new ItemRevisionQuery(session).searchID(productUnit.getProductID()).findAll();
        if (productRevisions == null || productRevisions.isEmpty()) {
            throw new InvalidUserInputException(
                    UserInputErrorEnum.WRONG_EFFECTIVITY_THE_PRODUCT_DOES_NOT_EXIST_OR_THE_UNIT_DOES_NOT_EXIST_FOR_THE_PRODUCT);
        }
        ItemRevision product = productRevisions.get(0); // Only one revision of Product

        // Find the units of the product
        session.loadProperties(product, PV_UNIT);
        ModelObject[] objects = product.getPropertyObject(PV_UNIT).getModelObjectArrayValue();
        session.loadProperties(objects);
        if (objects == null || objects.length == 0) {
            throw new InvalidUserInputException(
                    UserInputErrorEnum.WRONG_EFFECTIVITY_THE_PRODUCT_DOES_NOT_EXIST_OR_THE_UNIT_DOES_NOT_EXIST_FOR_THE_PRODUCT);
        }

        // Find Unit Revision
        List<ItemRevision> result = UnitRevision.getItemRevisionWithSameRange(session, productUnit.getUnitStr(), transformArray(objects));
        if (result.isEmpty()) {
            throw new InvalidUserInputException(
                    UserInputErrorEnum.WRONG_EFFECTIVITY_THE_PRODUCT_DOES_NOT_EXIST_OR_THE_UNIT_DOES_NOT_EXIST_FOR_THE_PRODUCT);
        }

        // Find Generic Revision
        List<ItemRevision> generics = getGenericItemRevision(session);
        if (generics == null) {
            throw new InvalidUserInputException(UserInputErrorEnum.INTERNAL_ERROR);
        }
        if (generics.isEmpty()) {
            throw new InvalidUserInputException(UserInputErrorEnum.GENERIC_DOES_NOT_EXIST_OR_ENTRY_EFFECTIVITY_IS_NOT_COMPATIBLE_WITH_THE_GENERIC);
        }
    }

    /**
     * Get the appropriate Generic Revision.
     *
     * @param session TcSession
     * @return ItemRevision the generic revision
     * @throws InvalidUserInputException for the throwable exception
     */
    private List<ItemRevision> getGenericItemRevision(final TcSession session) throws InvalidUserInputException {
        if (!AbstractGenericRevision.isGenericRevision(genericId)) {
            throw new InvalidUserInputException(UserInputErrorEnum.GENERIC_DOES_NOT_EXIST_OR_ENTRY_EFFECTIVITY_IS_NOT_COMPATIBLE_WITH_THE_GENERIC);
        }

        List<ItemRevision> genericRevisions = new ItemRevisionQuery(session).searchID(genericId).findAll();

        // Keep only the ItemRevision whose end item is the Product
        List<ItemRevision> checkedGenerics = ObjectInfoHelper.getRevisionWithSameEndItem(session, genericRevisions, productUnit.getProductID());
        genericRevisions.clear();

        // Compare effectivities
        List<ItemRevision> results = ObjectInfoHelper.getRevisionWithHighestRange(session, checkedGenerics, productUnit.getUnitStr());
        checkedGenerics.clear();
        return results;
    }
}
