package com.capgemini.reports.changeobjects.change;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.object.types.SnecmaObjectTypes;
import com.capgemini.reports.exceptions.NotSupportedException;
import com.capgemini.reports.snecmaobjects.generic.AbstractGeneric;
import com.capgemini.reports.teamcenter.queries.saved.WorkflowOnChangeQuery;
import com.capgemini.reports.workflows.Task;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.EPMTask;
import com.teamcenter.soa.client.model.strong.ItemRevision;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import static com.capgemini.framework.teamcenter.TeamcenterObjectTypes.CHANGE_REQUEST_REVISION;
import static com.capgemini.framework.teamcenter.object.SnecmaObjectProperties.*;

/**
 * Class representing a modification of a Unit.
 */
@Slf4j
public class TcChangeNoticeRevision extends AbstractChangeObject {
    private static final long serialVersionUID = -8781834231342513659L;

    private static final Pattern ETUDE_STUDY = Pattern.compile(".*(Etude|Study).*");

    public TcChangeNoticeRevision(final TcSession session, final ItemRevision itemRevision) {
        super(session, itemRevision);
    }

    public String getTypeModification() {
        return itemRevision.getPropertyObject(PV4_TYPE_MODIFICATION).getDisplayableValue();
    }

    @Override
    public List<Task> getWkfList() {
        List<Task> tasks = new ArrayList<>();
        for (EPMTask epmTask : new WorkflowOnChangeQuery(session).searchIDAndRevision(getItemId(), getRevisionId()).searchSequenceId(String.valueOf(getSequenceId())).findAll()) {
            if (!Task.TaskState.COMPLETED.equals(Task.TaskState.findState(epmTask.get_state()))) {
                tasks.add(new Task(session, epmTask));
            }
        }
        return tasks;
    }

    /**
     * Returns <code>true</code> if this generic's type is {@code Etude / Study}.
     *
     * @return true or false
     */
    public boolean isEtude() {
        return ETUDE_STUDY.matcher(getTypeModification()).matches();
    }

    public List<TcChangeRequestRevision> getImplementsCR() {
        List<TcChangeRequestRevision> implementsCR = new ArrayList<>();
        session.loadProperties(itemRevision, CM_IMPLEMENTS);
        ModelObject[] changes = itemRevision.getPropertyObject(CM_IMPLEMENTS).getModelObjectArrayValue();
        session.loadProperties(changes);
        for (ModelObject change : changes) {
            if (!SnecmaObjectTypes.isRecursively(CHANGE_REQUEST_REVISION, change.getTypeObject())) {
                log.warn("Found a {} object in the '{}' pseudo-folder of ChangeNotice {}, expecting only ChangeRequests. Skipping...",
                        change.getTypeObject().getName(), CM_IMPLEMENTS, getItemId());
                continue;
            }

            implementsCR.add(new TcChangeRequestRevision(session, (ItemRevision) change));
        }
        return implementsCR;
    }

    public List<AbstractGeneric> getListOfGenericRevWithOrWithoutRupture() {
        List<AbstractGeneric> generics = new ArrayList<>();
        List<ModelObject> genericsObjects = new ArrayList<>();
        session.loadProperties(itemRevision, PV_IMP_GENERICS_WITH_INTER, PV_IMP_GENERICS_WITHOUT_INTER);
        genericsObjects.addAll(itemRevision.getPropertyObject(PV_IMP_GENERICS_WITH_INTER).getModelObjectListValue());
        genericsObjects.addAll(itemRevision.getPropertyObject(PV_IMP_GENERICS_WITHOUT_INTER).getModelObjectListValue());
        session.loadProperties(genericsObjects.toArray(new ModelObject[genericsObjects.size()]));
        for (ModelObject genericsObject : genericsObjects) {
            try {
                generics.add(loadGeneric(genericsObject));
            } catch (NotSupportedException e) {
                log.warn("Unsupported object {} found in pseudo-folder {} or {}", genericsObject.getUid(), PV_IMP_GENERICS_WITH_INTER, PV_IMP_GENERICS_WITHOUT_INTER);
            }
        }
        return generics;
    }

    public List<AbstractGeneric> getListOfGenericRevWithRupture() {
        List<AbstractGeneric> generics = new ArrayList<>();
        session.loadProperties(itemRevision, PV_IMP_GENERICS_WITH_INTER);
        ModelObject[] genericsObjects = itemRevision.getPropertyObject(PV_IMP_GENERICS_WITH_INTER).getModelObjectArrayValue();
        session.loadProperties(genericsObjects);
        for (ModelObject genericsObject : genericsObjects) {
            try {
                generics.add(loadGeneric(genericsObject));
            } catch (NotSupportedException e) {
                log.warn("Unsupported object {} found in pseudo-folder {} or {}", genericsObject.getUid(), PV_IMP_GENERICS_WITH_INTER, PV_IMP_GENERICS_WITHOUT_INTER);
            }
        }
        return generics;
    }

    public List<AbstractGeneric> getListOfGenericRevWithoutRupture() {
        List<AbstractGeneric> generics = new ArrayList<>();
        session.loadProperties(itemRevision, PV_IMP_GENERICS_WITHOUT_INTER);
        ModelObject[] genericsObjects = itemRevision.getPropertyObject(PV_IMP_GENERICS_WITHOUT_INTER).getModelObjectArrayValue();
        session.loadProperties(genericsObjects);
        for (ModelObject genericsObject : genericsObjects) {
            try {
                generics.add(loadGeneric(genericsObject));
            } catch (NotSupportedException e) {
                log.warn("Unsupported object {} found in pseudo-folder {}", genericsObject.getUid(), PV_IMP_GENERICS_WITHOUT_INTER);
            }
        }
        return generics;
    }
}
