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

#ifndef CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_H_
#define CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_H_

#include <string>

#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "extensions/browser/extension_creator.h"
#include "extensions/buildflags/buildflags.h"

static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));

namespace extensions {

// Manages packing an extension on the file thread and reporting the result
// back to the UI.
// Ownership note: In "asynchronous" mode, `Client` has to make sure this
// class's instances are kept alive until OnPackSuccess|OnPackFailure is called.
// Therefore this class assumes that posting task with base::Unretained(this)
// is safe.
class PackExtensionJob {
 public:
  // Interface for people who want to use PackExtensionJob to implement.
  class Client {
   public:
    virtual void OnPackSuccess(const base::FilePath& crx_file,
                               const base::FilePath& key_file) = 0;
    virtual void OnPackFailure(const std::u16string& message,
                               ExtensionCreator::ErrorType error_type) = 0;

   protected:
    virtual ~Client() = default;
  };

  PackExtensionJob(Client* client,
                   const base::FilePath& root_directory,
                   const base::FilePath& key_file,
                   int run_flags);

  PackExtensionJob(const PackExtensionJob&) = delete;
  PackExtensionJob& operator=(const PackExtensionJob&) = delete;

  ~PackExtensionJob();

  // Starts the packing job.
  void Start();

  // The standard packing success message.
  static std::u16string StandardSuccessMessage(const base::FilePath& crx_file,
                                               const base::FilePath& key_file);

  void set_synchronous() { run_mode_ = RunMode::kSynchronous; }

 private:
  enum class RunMode { kSynchronous, kAsynchronous };

  // If `run_mode_` is kSynchronous, this is run on whichever thread calls it.
  void Run(scoped_refptr<base::SequencedTaskRunner> async_reply_task_runner);
  void ReportSuccessOnClientSequence(
      std::unique_ptr<base::FilePath> crx_file_out,
      std::unique_ptr<base::FilePath> key_file_out);
  void ReportFailureOnClientSequence(const std::u16string& error,
                                     ExtensionCreator::ErrorType error_type);

  const raw_ptr<Client> client_;  // Owns us.
  base::FilePath root_directory_;
  base::FilePath key_file_;
  RunMode run_mode_ = RunMode::kAsynchronous;
  int run_flags_;  // Bitset of ExtensionCreator::RunFlags values - we always
                   // assume kRequireModernManifestVersion, though.

  // Used to check methods that run on `client_`'s sequence.
  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_H_
