package com.capgemini.reports.teamcenter;

import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.framework.teamcenter.exceptions.NoTeamcenterConnectionException;
import com.capgemini.framework.teamcenter.object.pom.status.StatusEnum;
import com.capgemini.framework.teamcenter.policies.PolicyLocation;
import com.capgemini.framework.teamcenter.queries.saved.modelobject.ItemRevisionQuery;
import com.capgemini.reports.AbstractTeamcenterTest;
import com.capgemini.reports.exceptions.InvalidUserInputException;
import com.capgemini.reports.exceptions.NotFoundException;
import com.capgemini.reports.releasestatus.RevisionStatusAndDate;
import com.capgemini.reports.reports.parameters.Generics;
import com.capgemini.reports.reports.parameters.ProductUnit;
import com.google.common.base.Optional;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.Item;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import com.teamcenter.soa.client.model.strong.ReleaseStatus;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;

import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

@Slf4j
public class ObjectInfoHelperTest extends AbstractTeamcenterTest {

    private static final String PRODUCT_35R0 = "35R0";
    private static final String GENERIC_N24 = "N24";
    private static final String GENERIC_ASSEMB_24N = "24N";
    private static final int UNIT_60 = 60;

    // ************ For Alternate and DET tests **************
    private static final String[] EXPECTED_PARTS_ID_OF_ALTERNATE = {"1688M69P01", "1688M69P07"};
    private static final String[] EXPECTED_PARTS_ID_OF_DET = {"327-701-088-0", "327-701-105-0"};
    private static final String ALTERNATE_ID = "ART00010127";
    private static final String DET_ID = "620-037-104-0";

    @Override
    public PolicyLocation getPropertyPolicyIdentifier() {
        return DEFAULT_POLICY;
    }

    @Test
    public void testGetPartsInPseudoFolderOfAlternateRevision() throws KurtException {
        log.info("testGetPartsOfAlternateRevision() with Alternate Revision : " + ALTERNATE_ID);

        // GET ALTERNATE REVISION
        List<ItemRevision> alternateRevisionList = new ItemRevisionQuery(getSession()).searchIDAndRevision(ALTERNATE_ID, "A").findAll();
        Assert.assertNotNull(alternateRevisionList);
        Assert.assertFalse(alternateRevisionList.isEmpty());

        // GET ALTERNATE REVISION
        ItemRevision itemRevision = alternateRevisionList.get(0);
        Assert.assertNotNull(itemRevision);

        List<Item> listPartsOfAlternate = ObjectInfoHelper.getPartsInPseudoFolderOfAltOrDetRevision(getSession(), itemRevision);

        Assert.assertEquals(EXPECTED_PARTS_ID_OF_ALTERNATE.length, listPartsOfAlternate.size());

        String parts = "[ ";
        for (ModelObject modelObject : listPartsOfAlternate) {
            parts += modelObject.getPropertyDisplayableValue("item_id") + " ";
        }
        parts += "]";
        log.info("Found    IDs = {}", parts);
        log.info("Expected IDs = {}", Arrays.toString(EXPECTED_PARTS_ID_OF_ALTERNATE));
    }

    @Test
    public void testGetClosestGenerics()
            throws NotFoundException, InvalidUserInputException, NoTeamcenterConnectionException {
        log.info("testGetClosestGenerics ");
        ObjectInfoLoader infoLoader = new ObjectInfoLoader(getSession());
        ProductUnit product = new ProductUnit(PRODUCT_35R0, UNIT_60);

        // Test on a generic
        Generics generic = new Generics(product, GENERIC_N24, "");
        log.info("check Generic  " + generic.getID() + "with unit " + product.getUnit());
        List<ItemRevision> listGenericRevision = infoLoader.getGenericUnderProduct(generic, product);
        boolean isGenericHasAnUnitRevision = ObjectInfoHelper.getClosestGenerics(getSession(), generic.getID(), product.getUnit(), listGenericRevision);
        Assert.assertTrue("FAILED : Check  Generic is " + GENERIC_N24 + " hasn't an Unit Revision " + UNIT_60, isGenericHasAnUnitRevision);
        log.info("SUCCESS : Generic " + GENERIC_N24 + " has an Unit Revision with " + UNIT_60 + " result " + isGenericHasAnUnitRevision);

        // Test on a generic assemb
        Generics genericAssemb = new Generics(product, "", GENERIC_ASSEMB_24N);
        log.info("check Generic Assemb  " + generic.getID() + "with unit " + product.getUnit());
        List<ItemRevision> listGenericAssembRevision = infoLoader.getGenericUnderProduct(generic, product);
        boolean isGenericAssembHasAnUnitRevision =
                ObjectInfoHelper.getClosestGenerics(getSession(), genericAssemb.getID(), product.getUnit(), listGenericAssembRevision);
        Assert.assertTrue("FAILED : Check  Generic is " + GENERIC_N24 + " hasn't an Unit Revision " + UNIT_60, isGenericAssembHasAnUnitRevision);
        log.info("SUCCESS : Generic " + GENERIC_N24 + " has an Unit Revision with " + UNIT_60 + " result " + isGenericAssembHasAnUnitRevision);
    }

    @Test
    public void testGetPartsInPseudoFolderOfAltOrDetRevision() throws KurtException {
        log.info("testGetPartsInPseudoFolderOfAltOrDetRevision()");

        ItemRevision alt = new ItemRevisionQuery(getSession()).searchIDAndRevision("351-403-051-0", "A").findAll().get(0);
        Assert.assertNotNull(alt);
        List<Item> list = ObjectInfoHelper.getPartsInPseudoFolderOfAltOrDetRevision(getSession(), alt);
        Assert.assertNotNull(list);
        Assert.assertTrue(!list.isEmpty());

        for (Item item : list) {
            log.info("Parts in the psudo-folder : {}\t{}", item.getUid(), item.get_item_id());
        }
    }

    @Test
    public void testGetPartsOfDETRevision() throws KurtException {
        log.info("testGetPartsOfDETRevision() with DET Revision : " + DET_ID);

        // GET ALTERNATE REVISION LIST
        List<ItemRevision> alternateRevisionList = new ItemRevisionQuery(getSession()).searchIDAndRevision(DET_ID, "A").findAll();
        Assert.assertNotNull(alternateRevisionList);
        Assert.assertFalse(alternateRevisionList.isEmpty());

        // GET ALTERNATE REVISION
        ItemRevision itemRevision = alternateRevisionList.get(0);
        Assert.assertNotNull(itemRevision);

        List<Item> listPartsOfDET = ObjectInfoHelper.getPartsInPseudoFolderOfAltOrDetRevision(getSession(), itemRevision);
        Assert.assertNotNull(listPartsOfDET);
        Assert.assertEquals(EXPECTED_PARTS_ID_OF_DET.length, listPartsOfDET.size());

        String parts = "[ ";
        for (Item item : listPartsOfDET) {
            parts += item.get_item_id() + " ";
        }
        parts += "]";
        log.info("Found    IDs = {}", parts);
        log.info("Expected IDs = {}", Arrays.toString(EXPECTED_PARTS_ID_OF_DET));
    }

    @Test
    public void testGetRevisionWithHighestRange() throws NoTeamcenterConnectionException {
        List<ItemRevision> genericRevisions = new ItemRevisionQuery(getSession()).searchID("U24").findAll();
        List<ItemRevision> genericRevFiltered = ObjectInfoHelper.getRevisionWithHighestRange(getSession(), genericRevisions, "60");
        Assert.assertNotNull(genericRevFiltered);
        Assert.assertFalse(genericRevFiltered.isEmpty());

        // Verifying contents: 3 revisions have a unit range 10-UP: c, I, and K. no other revision have unit range between 10 and 60 (the limit)
        Assert.assertEquals(3, genericRevFiltered.size());
        boolean foundRevisionC = false;
        boolean foundRevisionI = false;
        boolean foundRevisionK = false;
        for (ItemRevision item : genericRevFiltered) {
            foundRevisionC = foundRevisionC || "C".equals(item.get_item_revision_id());
            foundRevisionI = foundRevisionI || "I".equals(item.get_item_revision_id());
            foundRevisionK = foundRevisionK || "K".equals(item.get_item_revision_id());
        }
        Assert.assertTrue(foundRevisionI && foundRevisionK);
    }

    @Test
    public void testGetModelObjectsInPseudoFolderUnderItemRevision() throws KurtException {
        List<ItemRevision> rfGenericRevisions = new ItemRevisionQuery(getSession()).searchIDAndRevision("00014868", "I").findAll();
        ItemRevision rfGeneric = rfGenericRevisions.get(0);
        Assert.assertNotNull(rfGeneric);

        List<ModelObject> resultsPseudoFolder = ObjectInfoHelper.getModelObjectsInPseudoFolderUnderItemRevision(getSession(), rfGeneric, "RFGenericBom");
        Assert.assertNotNull(resultsPseudoFolder);
        Assert.assertFalse(resultsPseudoFolder.isEmpty());
    }

    @Test
    public void testGetRevisionAndStatusWithMostRecentReleaseDate()
            throws NoTeamcenterConnectionException {
        // There are 13 revisions of this object!
        List<ItemRevision> revisions = new ItemRevisionQuery(getSession()).searchID("00014868").findAll();
        Optional<RevisionStatusAndDate> selectStatus = ObjectInfoHelper.getRevisionAndStatusWithMostRecentReleaseDate(getSession(), revisions, null);
        Assert.assertNotNull(selectStatus);
        Assert.assertTrue(selectStatus.isPresent());
        Assert.assertNotNull(selectStatus.get());
        Assert.assertNotNull(selectStatus.get().getItemRevision());
        Assert.assertNotNull(selectStatus.get().getReleaseDate());
        Assert.assertNotNull(selectStatus.get().getReleaseStatus());
        Assert.assertEquals(selectStatus.get().getItemRevision().get_item_id(), "00014868");
        Assert.assertEquals(selectStatus.get().getItemRevision().get_item_revision_id(), "B");
        Assert.assertEquals(selectStatus.get().getReleaseStatus().get_name(), "J3B");
    }

    @Test
    public void testGetRevisionAndStatusWithMostRecentReleaseDateNotFound() throws NoTeamcenterConnectionException {
        List<ItemRevision> revisions = new ItemRevisionQuery(getSession()).searchID("00065682").findAll();
        Optional<RevisionStatusAndDate> selectStatus =
                ObjectInfoHelper.getRevisionAndStatusWithMostRecentReleaseDate(getSession(), revisions, Calendar.getInstance());
        Assert.assertNotNull(selectStatus);
        Assert.assertFalse(selectStatus.isPresent());
    }

    @Test
    public void testGetRevisionWithMostRecentModificationDate() throws NoTeamcenterConnectionException {
        List<ItemRevision> revisions = new ItemRevisionQuery(getSession()).searchIDAndRevision("00014868", "I").findAll();
        Assert.assertNotNull(revisions);
        Assert.assertFalse(revisions.isEmpty());

        RevisionStatusAndDate selectedRevision =
                ObjectInfoHelper.getRevisionAndStatusWithMostRecentModificationDate(revisions, Calendar.getInstance());
        Assert.assertNotNull(selectedRevision);
        for (ItemRevision itemRev : revisions) {
            Assert.assertFalse(itemRev.get_last_mod_date().getTime().after(selectedRevision.getItemRevision().get_last_mod_date().getTime()));
        }
    }

    @Test
    public void testGetStatusWithMostRecentReleaseDate() throws NoTeamcenterConnectionException {
        List<ItemRevision> revisions = new ItemRevisionQuery(getSession()).searchIDAndRevision("309-162-004-0", "D").findAll();
        ItemRevision itemRev = revisions.get(0);
        ReleaseStatus selectStatus = ObjectInfoHelper.getStatusWithMostRecentReleaseDate(getSession(), itemRev, StatusEnum.EFFECTIVITY);
        Assert.assertNotNull(selectStatus);
        Assert.assertFalse(StatusEnum.EFFECTIVITY.getIdentifier().equals(selectStatus.get_name()));
    }
}
