package ru.kirillius.pf.sdn.core;

import lombok.SneakyThrows;
import ru.kirillius.pf.sdn.core.Networking.NetworkingService;
import ru.kirillius.pf.sdn.core.Subscription.SubscriptionService;
import ru.kirillius.pf.sdn.core.Util.Wait;
import ru.kirillius.utils.logging.SystemLogger;

import java.io.IOException;
import java.time.Duration;

/**
 * Periodically refreshes subscription content and network data according to runtime settings.
 */
public class ResourceUpdateService extends AppService {
    private final Thread updateThread;

    /**
     * Creates the service and prepares the background update worker.
     */
    public ResourceUpdateService(Context context) {
        super(context);

        updateThread = new Thread(new ThreadWorker());
    }

    /**
     * Starts the update thread; can only be invoked once.
     */
    public void start() {
        if (updateThread.isAlive()) {
            throw new IllegalStateException("Started already");
        }
        updateThread.start();
    }

    /**
     * Interrupts the update thread and stops scheduling tasks.
     */
    @Override
    public void close() throws IOException {
        updateThread.interrupt();
    }

    private final static String CTX = ResourceUpdateService.class.getSimpleName();

    /**
     * Background runner that performs scheduled resource maintenance tasks.
     */
    private class ThreadWorker implements Runnable {

        /**
         * Performs periodic subscription and network updates based on configuration intervals.
         */
        @SneakyThrows
        @Override
        public void run() {
            var updateService = context.getServiceManager().getService(AppUpdateService.class);
            var uptime = 0L;
            var config = context.getConfig();
            updateService.checkVersionForUpdate();
            while (!Thread.currentThread().isInterrupted()) {
                Thread.sleep(Duration.ofMinutes(1));
                uptime++;

                if (uptime % 15 == 0) {
                    updateService.checkVersionForUpdate();
                }

                if (config.getUpdateSubscriptionsInterval() > 0 && uptime % (config.getUpdateSubscriptionsInterval() * 60L) == 0) {
                    SystemLogger.message("Updating subscriptions", CTX);
                    var subscriptionManager = context.getServiceManager().getService(SubscriptionService.class);
                    subscriptionManager.triggerUpdate();
                    Wait.until(subscriptionManager::isUpdatingNow);
                    Wait.when(subscriptionManager::isUpdatingNow);
                }

                if (uptime % context.getConfig().getDomainLookupInterval() == 0) {
                    SystemLogger.message("Resolving domains...", CTX);
                    context.getServiceManager().getService(NetworkingService.class).performAutoresolve();
                }

                if (config.getUpdateASInterval() > 0 && uptime % (config.getUpdateASInterval() * 60L) == 0) {
                    SystemLogger.message("Updating cached AS", CTX);
                    var networkManager = context.getServiceManager().getService(NetworkingService.class);
                    networkManager.triggerUpdate(true);
                }
            }
        }
    }
}
