content: package allen.town.podcast.core.util.download;
  
  import android.content.Context;
  import android.util.Log;
  
  import androidx.annotation.NonNull;
  import androidx.appcompat.app.AlertDialog;
  import androidx.work.Constraints;
  import androidx.work.Data;
  import androidx.work.ExistingPeriodicWorkPolicy;
  import androidx.work.ExistingWorkPolicy;
  import androidx.work.NetworkType;
  import androidx.work.OneTimeWorkRequest;
  import androidx.work.PeriodicWorkRequest;
  import androidx.work.WorkManager;
  
  import java.util.Arrays;
  import java.util.Calendar;
  import java.util.concurrent.TimeUnit;
  
  import allen.town.focus_common.views.AccentMaterialDialog;
  import allen.town.podcast.core.R;
  import allen.town.podcast.core.pref.Prefs;
  import allen.town.podcast.core.service.FeedUpdateWorker;
  import allen.town.podcast.core.storage.DBTasks;
  import allen.town.podcast.core.util.NetworkUtils;
  
  public class AutoUpdateManager {
      private static final String WORK_ID_FEED_UPDATE = "allen.town.podcast.core.service.FeedUpdateWorker";
      private static final String WORK_ID_FEED_UPDATE_ONCE = WORK_ID_FEED_UPDATE + "Once";
      private static final String TAG = "AutoUpdateManager";
  
      private AutoUpdateManager() {
  
      }
  
      /**
       * Start / restart periodic auto feed refresh
       * @param context Context
       */
      public static void restartUpdateAlarm(Context context) {
          if (Prefs.isAutoUpdateDisabled()) {
              disableAutoUpdate(context);
          } else if (Prefs.isAutoUpdateTimeOfDay()) {
              int[] timeOfDay = Prefs.getUpdateTimeOfDay();
              Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
              restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1], context);
          } else {
              long milliseconds = Prefs.getUpdateInterval();
              restartUpdateIntervalAlarm(milliseconds, context);
          }
      }
  
      /**
       * Sets the interval in which the feeds are refreshed automatically
       */
      private static void restartUpdateIntervalAlarm(long intervalMillis, Context context) {
          Log.d(TAG, "Restarting update alarm.");
  
          PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(FeedUpdateWorker.class,
                  intervalMillis, TimeUnit.MILLISECONDS)
                  .setConstraints(getConstraints())
                  .build();
  
          WorkManager.getInstance(context).enqueueUniquePeriodicWork(
                  WORK_ID_FEED_UPDATE, ExistingPeriodicWorkPolicy.REPLACE, workRequest);
      }
  
      /**
       * Sets time of day the feeds are refreshed automatically
       */
      private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute, Context context) {
          Log.d(TAG, "Restarting update alarm.");
  
          Calendar now = Calendar.getInstance();
          Calendar alarm = (Calendar) now.clone();
          alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay);
          alarm.set(Calendar.MINUTE, minute);
          if (alarm.before(now) || alarm.equals(now)) {
              alarm.add(Calendar.DATE, 1);
          }
          long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis();
  
          OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
                  .setConstraints(getConstraints())
                  .setInitialDelay(triggerAtMillis, TimeUnit.MILLISECONDS)
                  .build();
  
          WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE,
                  ExistingWorkPolicy.REPLACE, workRequest);
      }
  
      /**
       * Run auto feed refresh once in background, as soon as what OS scheduling allows.
       *
       * Callers from UI should use {@link #runImmediate(Context)}, as it will guarantee
       * the refresh be run immediately.
       * @param context Context
       */
      public static void runOnce(Context context) {
          Log.d(TAG, "Run auto update once, as soon as OS allows.");
  
          OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
                  .setConstraints(getConstraints())
                  .setInitialDelay(0L, TimeUnit.MILLISECONDS)
                  .setInputData(new Data.Builder()
                          .putBoolean(FeedUpdateWorker.PARAM_RUN_ONCE, true)
                          .build()
                  )
                  .build();
  
          WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE_ONCE,
                  ExistingWorkPolicy.REPLACE, workRequest);
  
      }
  
      /**
       /**
       * Run auto feed refresh once in background immediately, using its own thread.
       *
       * Callers where the additional threads is not suitable should use {@link #runOnce(Context)}
       */
      public static void runImmediate(@NonNull Context context) {
          Log.d(TAG, "Run auto update immediately in background.");
          if (!NetworkUtils.networkAvailable()) {
              Log.d(TAG, "Ignoring: No network connection.");
          } else if (NetworkUtils.isFeedRefreshAllowed()) {
              startRefreshAllFeeds(context);
          } else {
              confirmMobileAllFeedsRefresh(context);
          }
      }
  
      private static void confirmMobileAllFeedsRefresh(final Context context) {
          AlertDialog.Builder builder = new AccentMaterialDialog(
                      context,
                      R.style.MaterialAlertDialogTheme
              )
                  .setTitle(R.string.feed_refresh_title)
                  .setMessage(R.string.confirm_mobile_feed_refresh_dialog_message)
                  .setPositiveButton(R.string.confirm_mobile_streaming_button_once,
                          (dialog, which) -> startRefreshAllFeeds(context))
                  .setNeutralButton(R.string.confirm_mobile_streaming_button_always, (dialog, which) -> {
                      Prefs.setAllowMobileFeedRefresh(true);
                      startRefreshAllFeeds(context);
                  })
                  .setNegativeButton(R.string.no, null);
          builder.show();
      }
  
      private static void startRefreshAllFeeds(final Context context) {
          new Thread(() -> DBTasks.refreshAllFeeds(
                  context.getApplicationContext(), true), "ManualRefreshAllFeeds").start();
      }
  
      public static void disableAutoUpdate(Context context) {
          WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_FEED_UPDATE);
      }
  
      private static Constraints getConstraints() {
          Constraints.Builder constraints = new Constraints.Builder();
  
          if (Prefs.isAllowMobileFeedRefresh()) {
              constraints.setRequiredNetworkType(NetworkType.CONNECTED);
          } else {
              constraints.setRequiredNetworkType(NetworkType.UNMETERED);
          }
          return constraints.build();
      }
  
  }
  