// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE_CLIENT_H_
#define COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE_CLIENT_H_

#include <optional>
#include <string>
#include <vector>

#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "net/base/isolation_info.h"
#include "net/http/http_response_headers.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace network {
class ResourceRequestBody;
class SharedURLLoaderFactory;
}  // namespace network

namespace download {

struct CompletionInfo;
struct DownloadMetaData;

// Contains request parameters that are not persisted and need to be re-provided
// by the client when a download is resumed after a restart.
struct COMPONENT_EXPORT(COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE)
    DownloadRequestParameters {
  DownloadRequestParameters();
  ~DownloadRequestParameters();
  DownloadRequestParameters(const DownloadRequestParameters&) = delete;
  DownloadRequestParameters& operator=(const DownloadRequestParameters&) = delete;
  DownloadRequestParameters(DownloadRequestParameters&& other);
  DownloadRequestParameters& operator=(DownloadRequestParameters&& other);

  // The request body to use for the download.
  scoped_refptr<network::ResourceRequestBody> post_body;

  // The custom URLLoaderFactory to use for the request.
  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;

  // The initiator of the request.
  std::optional<url::Origin> initiator;

  // The IsolationInfo to use for the request.
  std::optional<net::IsolationInfo> isolation_info;
};

// TODO(crbug.com/455486148): Rename to GetRequestParametersCallback.
using GetUploadDataCallback =
    base::OnceCallback<void(DownloadRequestParameters)>;

// The Client interface required by any feature that wants to start a download
// through the DownloadService.  Should be registered immediately at startup
// when the DownloadService is created (see the factory).
class COMPONENT_EXPORT(COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE) Client {
 public:
  // Used by OnDownloadFailed to determine the reason of the abort.
  enum class FailureReason {
    // Used when the download has been aborted after reaching a threshold where
    // we decide it is not worth attempting to start again.  This could be
    // either due to a specific number of failed retry attempts or a specific
    // number of wasted bytes due to the download restarting.
    NETWORK,

    // Used when the download was not completed before the
    // DownloadParams::cancel_after timeout.
    TIMEDOUT,

    // Used when the upload data was not received from the client before
    // timeout.
    UPLOAD_TIMEDOUT,

    // Used when the download was cancelled by the Client.
    CANCELLED,

    // Used when the download was aborted by the Client in response to the
    // download starting (see OnDownloadStarted()).
    ABORTED,

    // Used when the failure reason is unknown.  This generally means that we
    // detect that the download failed during a restart, but aren't sure exactly
    // what triggered the failure before shutdown.
    UNKNOWN,
  };

  virtual ~Client() = default;

  // Called when the DownloadService is initialized and ready to be interacted
  // with.  |downloads| is a list of all downloads the DownloadService is aware
  // of that are associated with this Client, including in-progress downloads
  // and recently completed downloads.
  // If |state_lost| is |true|, the service ran into an error initializing and
  // had to destroy all internal persisted state.  At this point any saved files
  // might not be available and any previously scheduled downloads are gone.
  virtual void OnServiceInitialized(
      bool state_lost,
      const std::vector<DownloadMetaData>& downloads) = 0;

  // Called when the DownloadService fails to initialize and should not be used.
  virtual void OnServiceUnavailable() = 0;

  // Will be called when a download has been started and the headers have been
  // retrieved. The download will be downloading at the time this call is made.
  virtual void OnDownloadStarted(
      const std::string& guid,
      const std::vector<GURL>& url_chain,
      const scoped_refptr<const net::HttpResponseHeaders>& headers);

  // Will be called when there is an update to the current progress state of the
  // underlying download.  Note that |bytes_downloaded| may go backwards if the
  // download had to be started over from the beginning due to an interruption.
  // This will be called frequently if the download is actively downloading,
  // with byte updates coming in as they are processed by the internal download
  // driver.
  virtual void OnDownloadUpdated(const std::string& guid,
                                 uint64_t bytes_uploaded,
                                 uint64_t bytes_downloaded);

  // Called when a download failed.  Check FailureReason for a list of possible
  // reasons why this failure occurred.  Note that this will also be called for
  // cancelled downloads. The CompletionInfo will be provided with the URL chain
  // and response headers filled in if available.
  virtual void OnDownloadFailed(const std::string& guid,
                                const download::CompletionInfo& info,
                                FailureReason reason);

  // Called when a download has been successfully completed.
  // The file and the database record will be automatically removed if it is not
  // renamed or deleted after a window of time (12 hours, but finch
  // configurable). The timeout is meant to be a failsafe to ensure that we
  // clean up properly.
  // TODO(dtrainor): Point to finch configurable timeout when it is added.
  // On iOS, the client needs to move the file immediately, and
  // the file is supposed to be deleted on next Chrome launch.
  virtual void OnDownloadSucceeded(const std::string& guid,
                                   const CompletionInfo& completion_info) = 0;

  // Called by the service to ask the client whether it is okay to remove a
  // completed file. If true, the file is deleted. If false, the file life time
  // is granted another grace period (12 hours, configurable) after which
  // the service will try again. If |force_delete| is true which happens when
  // the file was completed too long ago, the file will be deleted regardless of
  // the outcome of this function.
  virtual bool CanServiceRemoveDownloadedFile(const std::string& guid,
                                              bool force_delete) = 0;

  // Called by the service to ask the client to provide the upload data.
  // The client is responsible for posting the callback with an appropriate
  // ResourceRequestBody or nullptr, if it is a regular download. Not supported
  // on iOS.
  virtual void GetUploadData(const std::string& guid,
                             GetUploadDataCallback callback) = 0;

  // Called by the service to ask whether the client needs to repopulate request
  // parameters (e.g. re-providing URLLoaderFactory) upon a restart.
  virtual bool RequiresCustomRequestParameters() const;
};

}  // namespace download

#endif  // COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE_CLIENT_H_
