package com.atlassian.stash.internal.scheduling;

import com.atlassian.scheduler.SchedulerService;
import com.atlassian.scheduler.SchedulerServiceException;
import com.atlassian.stash.internal.ApplicationConstants;
import com.atlassian.stash.internal.spring.AbstractSmartLifecycle;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.OrderComparator;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @since 3.2
 */
@Component
public class ScheduledJobLifecycle extends AbstractSmartLifecycle {

    private static final Logger log = LoggerFactory.getLogger(ScheduledJobLifecycle.class);

    private final SchedulerService schedulerService;
    private final ImmutableList<ScheduledJobSource> sources;

    @Autowired
    public ScheduledJobLifecycle(SchedulerService schedulerService,
                                 List<ScheduledJobSource> sources) {
        sources = Lists.newArrayList(sources);
        OrderComparator.sort(sources);

        this.schedulerService = schedulerService;
        this.sources = ImmutableList.copyOf(sources);
    }

    @Override
    public int getPhase() {
        return ApplicationConstants.LIFECYCLE_PHASE_SCHEDULED_JOBS;
    }

    @Override
    public void start() {
        log.debug("Applying {} job sources", sources.size());
        for (ScheduledJobSource source : sources) {
            String name = getName(source);
            try {
                log.debug("Scheduling jobs for {}", name);
                source.schedule(schedulerService);
            } catch (SchedulerServiceException e) {
                log.error("Failed to schedule jobs for {}", name, e);
            }
        }

        super.start();
    }

    @Override
    public void stop() {
        for (ScheduledJobSource source : sources.reverse()) {
            String name = getName(source);
            try {
                log.debug("Unscheduling jobs for {}", name);
                source.unschedule(schedulerService);
            } catch (SchedulerServiceException e) {
                log.error("Failed to unschedule jobs for {}", name, e);
            }
        }

        super.stop();
    }

    private static String getName(ScheduledJobSource source) {
        return AopUtils.getTargetClass(source).getSimpleName();
    }

}
