/***********************************************************************************************************
 * Name         : BatchJobsMonitor
 * Purpose      : Monitors TempFormResponseBatch and WelcomeEmailBatch, and starts it if it is not running
 **********************************************************************************************************/

public with sharing class BatchJobsMonitor implements Schedulable, Database.Stateful {
    public void monitor() {
        List<AsyncApexJob> jobsTFR = Database.query(BatchJobUtils.getMonitorQuery('TempFormResponseBatch'));
        List<AsyncApexJob> jobsWE = Database.query(BatchJobUtils.getMonitorQuery('WelcomeEmailBatch'));

        if (shouldRestart(jobsTFR)) {
            Database.executeBatch(new TempFormResponseBatch());
            BatchJobUtils.sendEmail(
                ConfigUtils.TFR_MONITOR_EMAIL_RECIPIENTS,
                ConfigUtils.TFR_MONITOR_EMAIL_SENDER,
                ConfigUtils.TFR_MONITOR_EMAIL_SUBJECT,
                ConfigUtils.TFR_MONITOR_EMAIL_BODIES,
                'Jobs.csv',
                jobsTFR
            );
        }
        if (shouldRestart(jobsWE)) {
            Database.executeBatch(new WelcomeEmailBatch());
            BatchJobUtils.sendEmail(
                ConfigUtils.WE_MONITOR_EMAIL_RECIPIENTS,
                ConfigUtils.WE_MONITOR_EMAIL_SENDER,
                ConfigUtils.WE_MONITOR_EMAIL_SUBJECT,
                ConfigUtils.WE_MONITOR_EMAIL_BODIES,
                'Jobs.csv',
                jobsWE
            );
        }
    }

    /**
     * Method Name  : shouldRestart
     * Description  : check if the job should be restarted or not
     * @return Boolean -> true in case it should be restarted, false if shoudn't.
     */
    @TestVisible 
    private Boolean shouldRestart(List<AsyncApexJob> jobsList) {
        for (AsyncApexJob job : jobsList) {
            if (BatchJobUtils.ACTIVE_JOB_STATUS.contains(job.Status)) {
                return false;
            }
            if (
                job.CreatedDate >
                System.now().addMinutes(-ConfigUtils.getConfigInt(ConfigUtils.JOBS_MONITOR_CREATED_MINUTES))
            ) {
                return false;
            }
        }
        return true;
    }

    public void execute(SchedulableContext sc) {
        this.monitor();
    }

    public static void schedule() {
        BatchJobUtils.scheduleJob(
            new BatchJobsMonitor(),
            ConfigUtils.getConfigString(ConfigUtils.JOBS_MONITOR_CRON_EXPS)
        );
    }
}