package specs.scheduler;

import io.sphere.sdk.payments.Payment;
import io.sphere.sdk.payments.PaymentStatus;
import org.apache.commons.lang3.StringUtils;
import org.concordion.api.MultiValueResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import specs.response.BasePaymentFixture;

import static java.util.Optional.ofNullable;

/**
 * Helper class to test scheduled jobs on both tenants.
 * <p>
 * The tenants are represented and {@link #paymentFixture} instance, implementing respectively the first (base) or the
 * second tenant {@link specs.multitenancy.BaseTenant2Fixture}.
 */
public class ScheduledJobFixtureHelper {

    private static Logger LOG = LoggerFactory.getLogger(ScheduledJobShortFixture.class);

    private final BasePaymentFixture paymentFixture;

    public ScheduledJobFixtureHelper(BasePaymentFixture paymentFixture) {
        this.paymentFixture = paymentFixture;
    }

    public MultiValueResult createPayment(String paymentName,
                                                 String paymentMethod,
                                                 String transactionType,
                                                 String centAmount,
                                                 String currencyCode) throws Exception {

        Payment payment = paymentFixture.createAndSavePayment(paymentName, paymentMethod, transactionType, centAmount, currencyCode);

        return MultiValueResult.multiValueResult()
                .with("id", payment.getId())
                .with("version", payment.getVersion())
                .with("paymentStatus", ofNullable(payment.getPaymentStatus()).map(PaymentStatus::getInterfaceCode).orElse(null))
                .with("interfaceInteractionsSize", payment.getInterfaceInteractions().size())
                .with("transactionsSize", payment.getTransactions().size())
                .with("createdAt", payment.getCreatedAt())
                .with("lastModifiedAt", payment.getLastModifiedAt())
                .with("isNotModified", payment.getCreatedAt().equals(payment.getLastModifiedAt()));
    }

    public MultiValueResult verifyPaymentIsHandled(String paymentName) throws Exception {
        Payment payment = paymentFixture.fetchPaymentByLegibleName(paymentName);

        // wait once, if necessary
        if (payment.getPaymentStatus() == null || StringUtils.isBlank(payment.getPaymentStatus().getInterfaceCode())) {

            // how much time to wait till the next scheduled job is definitely started
            long secondsToWait = payment.getCreatedAt()
                    .plusSeconds(waitSecondsTimeout())
                    .minusSeconds(System.currentTimeMillis() / 1000).toEpochSecond();

            if (secondsToWait > 0) {
                LOG.info("Wait up to {} seconds for scheduled job to run", secondsToWait);
                Thread.sleep(secondsToWait * 1000);
            }

            payment = paymentFixture.fetchPaymentByLegibleName(paymentName);
        }

        return MultiValueResult.multiValueResult()
                .with("version", payment.getVersion())
                .with("paymentStatus", ofNullable(payment.getPaymentStatus()).map(PaymentStatus::getInterfaceCode).orElse(null))
                .with("interfaceInteractionsSize", payment.getInterfaceInteractions().size())
                .with("transactionsSize", payment.getTransactions().size())
                .with("lastModifiedAt", payment.getLastModifiedAt())
                .with("hasBeenModified", payment.getCreatedAt().compareTo(payment.getLastModifiedAt()) < 0);
    }

    public static int waitSecondsTimeout() {
        return 40; // we make 10 seconds overlap to let the job complete
    }

}

@@ -19,16 +19,81 @@
 duler;%0A%0A
+import com.commercetools.pspadapter.payone.config.ServiceConfig;%0A
 import i
@@ -962,32 +962,460 @@
 Fixture;%0A    %7D%0A%0A
+    /**%0A     * Create a payment, but don't handle it%0A     * @param paymentName      test payment alias%0A     * @param paymentMethod    payone payment method name%0A     * @param transactionType  payone payment transaction type%0A     * @param centAmount       payment amount%0A     * @param currencyCode     payment currency%0A     * @return map of created payment properties%0A     * @throws Exception any exceptions in the tests%0A     */%0A
     public Multi
@@ -2574,32 +2574,306 @@
 dAt()));%0A    %7D%0A%0A
+    /**%0A     * Verify the %7B@code paymentName%7D is automatically handled by (short) scheduled task.%0A     * @param paymentName payment alias%0A     * @return map of the payment properties after waiting scheduled task.%0A     * @throws Exception any exceptions in the tests%0A     */%0A
     public Multi
@@ -4338,24 +4338,739 @@
  0);%0A    %7D%0A%0A
+    /**%0A     * A maximum duration we wait for a payment is handled by (short) scheduled task.%0A     * %3Cp%3E%0A     * %3Cb%3ENote:%3C/b%3E%3Cul%3E%0A     *     %3Cli%3Ethis test is depended on actual service's %7B@link ServiceConfig#getScheduledJobCronForShortTimeFramePoll()%7D%0A     * value, which is configured by %7B@code SHORT_TIME_FRAME_SCHEDULED_JOB_CRON%7D environment variable%0A     * (or fallback to default one). We expect the short time-frame is %22every 30 seconds%22 (%3Cb%3E%7B@code 0/30 * * * * ? *%7D%3C/b%3E.%0A     * Adjust this value if you change short time-frame schedule in the Heroku service.%3C/li%3E%0A     *     %3Cli%3EWe added 10 second gap to let the job complete if any lags occurred.%3C/li%3E%0A     * %3C/ul%3E%0A     *%0A     * @return 40 (seconds)%0A     */%0A
     public s
@@ -5124,62 +5124,8 @@
  40;
- // we make 10 seconds overlap to let the job complete
 %0A   

add comments to ScheduledJobFixtureHelper