/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.gnd.persistence.remote;

import android.net.Uri;
import com.google.android.gms.tasks.Task;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import java.io.File;
import java.util.Objects;
import java8.util.StringJoiner;
import javax.inject.Inject;
import javax.inject.Singleton;
import timber.log.Timber;

// TODO: Add column to Observation table for storing uploaded media urls
// TODO: Synced to remote db as well
// TODO: Extract a generic interface so that we have an internal API to switch providers
@Singleton
public class FirestoreStorageManager {

  private static final String MEDIA_ROOT_DIR = "uploaded_media";
  private final StorageReference storageReference;

  @Inject
  FirestoreStorageManager(StorageReference storageReference) {
    this.storageReference = storageReference;
  }

  /**
   * Generates destination path for saving the image to Firestore Storage.
   *
   * <p>/uploaded_media/{project_id}/{form_id}/{feature_id}/{filename.jpg}
   */
  public static String getRemoteImagePath(
      String projectId, String formId, String featureId, String filename) {
    return new StringJoiner(File.separator)
        .add(MEDIA_ROOT_DIR)
        .add(projectId)
        .add(formId)
        .add(featureId)
        .add(filename)
        .toString();
  }

  public Task<Uri> getDownloadUrl(String path) {
    return storageReference.child(path).getDownloadUrl();
  }

  /** Upload file to Firebase Storage. */
  public String uploadMediaFromFile(File file, String destinationPath) {
    StorageReference reference = storageReference.child(destinationPath);
    UploadTask task = reference.putFile(Uri.fromFile(file));

    uploadMediaToFirebaseStorage(task, destinationPath);
    fetchDownloadUrl(reference, task);
    return reference.getPath();
  }

  private void uploadMediaToFirebaseStorage(UploadTask uploadTask, String fileName) {
    // TODO: Create UploadState enum and use RxJava to broadcast upload state globally.
    // use our util RxTask to convert the task to a Single.
    uploadTask
        .addOnCanceledListener(
            () -> {
              Timber.d("Uploading canceled: %s", fileName);
            })
        .addOnCompleteListener(
            task -> {
              Timber.d("Uploading completed: %s", fileName);
            })
        .addOnFailureListener(
            e -> {
              Timber.e(e, "Uploading failed: %s", fileName);
            })
        .addOnSuccessListener(
            taskSnapshot -> {
              Timber.d("Uploading succeeded: %s", fileName);
            })
        .addOnProgressListener(
            taskSnapshot -> {
              double percentCompleted =
                  100.0 * taskSnapshot.getBytesTransferred() / taskSnapshot.getTotalByteCount();
              Timber.d("Uploading in progress: %s %f", fileName, percentCompleted);
            });
  }

  private void fetchDownloadUrl(StorageReference reference, UploadTask uploadTask) {
    uploadTask
        .continueWithTask(
            task -> {
              if (!task.isSuccessful()) {
                throw Objects.requireNonNull(task.getException());
              }
              // Continue with the task to get the download URL
              return reference.getDownloadUrl();
            })
        .addOnCompleteListener(
            task -> {
              // TODO save to local database
              if (task.isSuccessful()) {
                Uri downloadUri = task.getResult();
                Timber.d("Uploaded to : %s", downloadUri);
              }
            });
  }
}

@@ -832,34 +832,8 @@
 le;%0A
-import java.util.Objects;%0A
 impo
@@ -860,16 +860,16 @@
 Joiner;%0A
+
 import j
@@ -2077,22 +2077,20 @@
  public 
-String
+void
  uploadM
@@ -2274,17 +2274,16 @@
 file));%0A
-%0A
     uplo
@@ -2335,79 +2335,8 @@
 h);%0A
-    fetchDownloadUrl(reference, task);%0A    return reference.getPath();%0A
   %7D%0A
@@ -3300,24 +3300,24 @@
 yteCount();%0A
+
             
@@ -3411,697 +3411,7 @@
 %0A  %7D
-%0A%0A  private void fetchDownloadUrl(StorageReference reference, UploadTask uploadTask) %7B%0A    uploadTask%0A        .continueWithTask(%0A            task -%3E %7B%0A              if (!task.isSuccessful()) %7B%0A                throw Objects.requireNonNull(task.getException());%0A              %7D%0A              // Continue with the task to get the download URL%0A              return reference.getDownloadUrl();%0A            %7D)%0A        .addOnCompleteListener(%0A            task -%3E %7B%0A              // TODO save to local database%0A              if (task.isSuccessful()) %7B%0A                Uri downloadUri = task.getResult();%0A                Timber.d(%22Uploaded to : %25s%22, downloadUri);%0A              %7D%0A            %7D);%0A  %7D
 %0A%7D%0A

Clean FirebaseStorageManager