package org.sufficientlysecure.keychain.keysync;


import java.util.concurrent.atomic.AtomicBoolean;

import android.app.NotificationManager;
import android.content.Context;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationCompat.Builder;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import org.sufficientlysecure.keychain.Constants.NotificationIds;
import org.sufficientlysecure.keychain.NotificationChannelManager;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.network.orbot.OrbotHelper;
import org.sufficientlysecure.keychain.operations.KeySyncOperation;
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity;
import org.sufficientlysecure.keychain.util.ResourceUtils;
import timber.log.Timber;


public class KeyserverSyncWorker extends Worker {
    private AtomicBoolean cancellationSignal = new AtomicBoolean(false);

    public KeyserverSyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        KeyWritableRepository keyWritableRepository = KeyWritableRepository.create(getApplicationContext());

        Timber.d("Starting key sync…");
        Progressable notificationProgressable = notificationShowForProgress();
        KeySyncOperation keySync = new KeySyncOperation(getApplicationContext(), keyWritableRepository, notificationProgressable, cancellationSignal);
        ImportKeyResult result = keySync.execute(KeySyncParcel.createRefreshOutdated(), CryptoInputParcel.createCryptoInputParcel());
        return handleUpdateResult(result);
    }

    /**
     * Since we're returning START_REDELIVER_INTENT in onStartCommand, we need to remember to call
     * stopSelf(int) to prevent the Intent from being redelivered if our work is already done
     *
     * @param result
     *         result of keyserver sync
     */
    private Result handleUpdateResult(ImportKeyResult result) {
        if (result.isPending()) {
            Timber.d("Orbot required for sync but not running, attempting to start");
            // result is pending due to Orbot not being started
            // try to start it silently, if disabled show notifications
            new OrbotHelper.SilentStartManager() {
                @Override
                protected void onOrbotStarted() {
                }

                @Override
                protected void onSilentStartDisabled() {
                    OrbotRequiredDialogActivity.showOrbotRequiredNotification(getApplicationContext());
                }
            }.startOrbotAndListen(getApplicationContext(), false);
            return Result.retry();
        } else if (isStopped()) {
            Timber.d("Keyserver sync cancelled");
            return Result.failure();
        } else {
            Timber.d("Keyserver sync completed: Updated: %d, Failed: %d", result.mUpdatedKeys, result.mBadKeys);
            return Result.success();
        }
    }

    private Progressable notificationShowForProgress() {
        final Context context = getApplicationContext();
        NotificationManager notificationManager =
                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager == null) {
            return null;
        }

        NotificationChannelManager.getInstance(context).createNotificationChannelsIfNecessary();

        NotificationCompat.Builder builder = new Builder(context, NotificationChannelManager.KEYSERVER_SYNC)
                .setSmallIcon(R.drawable.ic_stat_notify_24dp)
                .setLargeIcon(ResourceUtils.getDrawableAsNotificationBitmap(context, R.mipmap.ic_launcher))
                .setContentTitle(context.getString(R.string.notify_title_keysync))
                .setPriority(NotificationCompat.PRIORITY_MIN)
                .setTimeoutAfter(5000)
                .setVibrate(null)
                .setSound(null)
                .setProgress(0, 0, true);

        return new Progressable() {
            @Override
            public void setProgress(Integer ignored, int current, int total) {
                if (total == 0) {
                    notificationManager.cancel(NotificationIds.KEYSERVER_SYNC);
                    return;
                }

                builder.setProgress(total, current, false);
                if (current == total) {
                    builder.setContentTitle(context.getString(R.string.notify_title_keysync_finished, total));
                    builder.setContentText(null);
                } else {
                    builder.setContentText(context.getString(R.string.notify_content_keysync, current, total));
                }
                notificationManager.notify(NotificationIds.KEYSERVER_SYNC, builder.build());
            }

            @Override
            public void setPreventCancel() {
            }
        };
    }

    @Override
    public void onStopped() {
        super.onStopped();
        cancellationSignal.set(true);
    }
}
