package com.capgemini.reports.execution.posting;

import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.quartz.SchedulerServer;
import com.capgemini.reports.quartz.TriggerPreparator;
import com.capgemini.reports.quartz.jobs.DelayedJob;
import lombok.AllArgsConstructor;
import org.quartz.*;

import java.util.HashMap;
import java.util.Map;

/** This strategy can delay a report execution until a later time in the day, using a combination of Quartz and HornetQ. */
@AllArgsConstructor
public class DelayedPostingStategy implements IPostingStrategy {

    private final SchedulerServer schedulingServer;

    /** Key linking to an {@link AbstractExecutionReport} in the {@link JobDetail} of a delayed Quartz job. */
    public static final String JOB_DETAIL_KEY_REPORT = "Report";

    @Override
    public void handleRequest(final AbstractExecutionReport<?, ?> report) throws SchedulerException {
        // Prepare the Trigger
        Trigger trigger = TriggerPreparator.prepareDelayedTrigger(report.getReportTechnicalUid(), report.getPriorityCode());

        // Prepare the Job
        JobDetail job = getDelayedJobDetail(report, trigger);

        // Delay the launch into the queue
        try {
            schedulingServer.schedule(job, trigger);
        } catch (SchedulerException e) {
            throw new SchedulerException("Unable to delay the job associated to the report " + report.getReportIdentifier().getReportName() + " " + report.getReportTechnicalUid(), e);
        }
    }

    /**
     * Get the JobDetail for a delayed execution of report.
     * 
     * @param report {@link AbstractExecutionReport} - the implementation of the report
     * @param trigger {@link Trigger} - the trigger used for the scheduling
     * @return the JobDetail
     */
    private JobDetail getDelayedJobDetail(final AbstractExecutionReport<?, ?> report, final Trigger trigger) {
        // Initialize the parameter used in the execution of the job
        Map<String, Object> paramJob = new HashMap<>();
        paramJob.put(JOB_DETAIL_KEY_REPORT, report);

        // Define the job and tie it to our SimpleJob class
        JobKey jobKey = trigger.getJobKey();

        // The method requestRecovery ask scheduler to re-execute this job
        return JobBuilder.newJob(DelayedJob.class).withIdentity(jobKey.getName(), jobKey.getGroup()).requestRecovery().usingJobData(new JobDataMap(paramJob)).build();
    }
}
