package com.capgemini.reports.execution.actions.ondataset;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.UnableToCreateStatusException;
import com.capgemini.framework.teamcenter.statuating.StatusSetter;
import com.capgemini.reports.database.javabean.DbReport;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.execution.actions.AbstractPostExecutionStep;
import com.teamcenter.soa.client.model.ModelObject;
import com.teamcenter.soa.client.model.strong.ReleaseStatus;
import com.teamcenter.soa.client.model.strong.WorkspaceObject;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

import javax.inject.Provider;
import java.io.Serializable;

/**
 * This class is an action that can be used to set a {@link ReleaseStatus} on a {@link ModelObject} with a given name.
 *
 * @param <T> the class of the calling report
 */
@Slf4j
@EqualsAndHashCode(callSuper = true)
public class SetStatusAction<T extends AbstractExecutionReport<T, ?>> extends AbstractPostExecutionStep<T, Void> {

    private static final long serialVersionUID = -1516821856454786852L;

    private final SerializableProvider<? extends ModelObject> targetProvider;
    private final SerializableProvider<String> statusNameProvider;

    /**
     * Creates a {@link SetStatusAction} to be executed when the report has completed its execution.
     *
     * @param <TP>           the class of the target provider. Must be both {@link Serializable} and a {@link ModelObject} {@link Provider}.
     * @param <NP>           the class of the name provider. Must be both {@link Serializable} and a {@link String} {@link Provider}.
     * @param targetProvider a {@link Provider} which will eventually {@link Provider#get() provide} a target {@link ModelObject}.
     * @param nameProvider   a {@link Provider} which will eventually {@link Provider#get() provide} a status name.
     * @param reportClass    the Class of the calling report.
     */
    public <TP extends Provider<? extends ModelObject> & Serializable, NP extends Provider<String> & Serializable> SetStatusAction(TP targetProvider,
                                                                                                                                   NP nameProvider, Class<T> reportClass) {
        super(reportClass);
        // Both casts are safe because a Serializable Provider is both Serializable... and a Provider
        this.targetProvider = (SerializableProvider<? extends ModelObject>) targetProvider;
        this.statusNameProvider = (SerializableProvider<String>) nameProvider;
    }

    /**
     * Sets a status on a {@link ModelObject}.
     *
     * @param session    an active Tc session
     * @param target     the target ModelObject
     * @param statusName the desired status name
     * @return the newly created status
     * @throws UnableToCreateStatusException thrown if unable to create the status.
     */
    public static ReleaseStatus setStatus(final TcSession session, final ModelObject target, String statusName)
            throws UnableToCreateStatusException {
        return new StatusSetter(session).putStatus((WorkspaceObject) target, statusName);
    }

    @Override
    public Void performPostActionOnReport(final TcSession session, final T report, final DbReport theExecutingReport,
                                          final String fileNameWithExtension) throws UnableToCreateStatusException {
        // Get the target
        ModelObject target = targetProvider.get();

        // Set the TcReleaseStatus on the dataset
        log.debug("Wokflow launch: Adding 'Frozen' status to the object {}", target.getUid());
        setStatus(session, target, statusNameProvider.get());
        return null;
    }

}
