// Copyright 2022 The Cobalt Authors. All Rights Reserved.
//
// 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
//
//     http://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.

#include "cobalt/worker/service_worker_persistent_settings.h"

#include <list>
#include <map>
#include <memory>
#include <string>
#include <utility>

#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/trace_event.h"
#include "cobalt/network/disk_cache/resource_type.h"
#include "cobalt/persistent_storage/persistent_settings.h"
#include "cobalt/script/exception_message.h"
#include "cobalt/script/promise.h"
#include "cobalt/script/script_value.h"
#include "cobalt/web/cache_utils.h"
#include "cobalt/worker/service_worker_context.h"
#include "cobalt/worker/service_worker_jobs.h"
#include "cobalt/worker/service_worker_registration_object.h"
#include "cobalt/worker/service_worker_update_via_cache.h"
#include "cobalt/worker/worker_consts.h"
#include "cobalt/worker/worker_global_scope.h"
#include "net/base/completion_once_callback.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace cobalt {
namespace worker {

namespace {
// ServiceWorkerRegistrationMap persistent settings keys.
const char kSettingsKeyList[] = "key_list";

// ServiceWorkerRegistrationObject persistent settings keys.
const char kSettingsStorageKeyKey[] = "storage_key";
const char kSettingsScopeStringKey[] = "scope_string";
const char kSettingsScopeUrlKey[] = "scope_url";
const char kSettingsUpdateViaCacheModeKey[] = "update_via_cache_mode";
const char kSettingsWaitingWorkerKey[] = "waiting_worker";
const char kSettingsActiveWorkerKey[] = "active_worker";
const char kSettingsLastUpdateCheckTimeKey[] = "last_update_check_time";

// ServicerWorkerObject persistent settings keys.
const char kSettingsOptionsNameKey[] = "options_name";
const char kSettingsScriptUrlKey[] = "script_url";
const char kSettingsScriptResourceMapScriptUrlsKey[] =
    "script_resource_map_script_urls";
const char kSettingsSetOfUsedScriptsKey[] = "set_of_used_scripts";
const char kSettingsSkipWaitingKey[] = "skip_waiting";
const char kSettingsClassicScriptsImportedKey[] = "classic_scripts_imported";
const char kSettingsRawHeadersKey[] = "raw_headers";

bool CheckPersistentValue(
    std::string key_string, std::string settings_key,
    base::flat_map<std::string, std::unique_ptr<base::Value>>& dict,
    base::Value::Type type) {
  if (!dict.contains(settings_key)) {
    DLOG(INFO) << "Key: " << key_string << " does not contain " << settings_key;
    return false;
  } else if (!(dict[settings_key]->type() == type)) {
    DLOG(INFO) << "Key: " << key_string << " " << settings_key
               << " is of type: " << dict[settings_key]->type()
               << ", but expected type is: " << type;
    return false;
  }
  return true;
}
}  // namespace

ServiceWorkerPersistentSettings::ServiceWorkerPersistentSettings(
    const Options& options)
    : options_(options) {
  persistent_settings_.reset(new cobalt::persistent_storage::PersistentSettings(
      WorkerConsts::kSettingsJson));
  persistent_settings_->ValidatePersistentSettings();
  DCHECK(persistent_settings_);
}

void ServiceWorkerPersistentSettings::ReadServiceWorkerRegistrationMapSettings(
    std::map<RegistrationMapKey,
             scoped_refptr<ServiceWorkerRegistrationObject>>&
        registration_map) {
  std::vector<base::Value> key_list =
      persistent_settings_->GetPersistentSettingAsList(kSettingsKeyList);
  std::set<std::string> unverified_key_set;
  for (auto& key : key_list) {
    if (key.is_string()) {
      unverified_key_set.insert(key.GetString());
    }
  }
  for (auto& key_string : unverified_key_set) {
    auto dict =
        persistent_settings_->GetPersistentSettingAsDictionary(key_string);
    if (dict.empty()) {
      DLOG(INFO) << "Key: " << key_string << " does not exist in "
                 << WorkerConsts::kSettingsJson;
      continue;
    }
    if (!CheckPersistentValue(key_string, kSettingsStorageKeyKey, dict,
                              base::Value::Type::STRING))
      continue;
    url::Origin storage_key =
        url::Origin::Create(GURL(dict[kSettingsStorageKeyKey]->GetString()));

    if (!CheckPersistentValue(key_string, kSettingsScopeUrlKey, dict,
                              base::Value::Type::STRING))
      continue;
    GURL scope(dict[kSettingsScopeUrlKey]->GetString());

    if (!CheckPersistentValue(key_string, kSettingsUpdateViaCacheModeKey, dict,
                              base::Value::Type::INTEGER))
      continue;
    ServiceWorkerUpdateViaCache update_via_cache =
        static_cast<ServiceWorkerUpdateViaCache>(
            dict[kSettingsUpdateViaCacheModeKey]->GetInt());

    if (!CheckPersistentValue(key_string, kSettingsScopeStringKey, dict,
                              base::Value::Type::STRING))
      continue;
    std::string scope_string(dict[kSettingsScopeStringKey]->GetString());

    RegistrationMapKey key(storage_key, scope_string);
    scoped_refptr<ServiceWorkerRegistrationObject> registration(
        new ServiceWorkerRegistrationObject(storage_key, scope,
                                            update_via_cache));

    auto worker_key = kSettingsWaitingWorkerKey;
    if (!CheckPersistentValue(key_string, worker_key, dict,
                              base::Value::Type::DICTIONARY)) {
      worker_key = kSettingsActiveWorkerKey;
      if (!CheckPersistentValue(key_string, worker_key, dict,
                                base::Value::Type::DICTIONARY))
        continue;
    }
    if (!ReadServiceWorkerObjectSettings(
            registration, key_string, std::move(dict[worker_key]), worker_key))
      continue;

    if (CheckPersistentValue(key_string, kSettingsLastUpdateCheckTimeKey, dict,
                             base::Value::Type::STRING)) {
      int64_t last_update_check_time =
          std::atol(dict[kSettingsLastUpdateCheckTimeKey]->GetString().c_str());
      registration->set_last_update_check_time(
          base::Time::FromDeltaSinceWindowsEpoch(
              base::TimeDelta::FromMicroseconds(last_update_check_time)));
    }

    key_set_.insert(key_string);
    registration_map.insert(std::make_pair(key, registration));
    registration->set_is_persisted(true);

    options_.service_worker_context->message_loop()->task_runner()->PostTask(
        FROM_HERE,
        base::BindOnce(&ServiceWorkerContext::Activate,
                       base::Unretained(options_.service_worker_context),
                       registration));

    auto job = options_.service_worker_context->jobs()->CreateJobWithoutPromise(
        ServiceWorkerJobs::JobType::kUpdate, storage_key, scope,
        registration->waiting_worker()->script_url());
    options_.service_worker_context->message_loop()->task_runner()->PostTask(
        FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
                                  base::Unretained(
                                      options_.service_worker_context->jobs()),
                                  std::move(job)));
  }
}

bool ServiceWorkerPersistentSettings::ReadServiceWorkerObjectSettings(
    scoped_refptr<ServiceWorkerRegistrationObject> registration,
    std::string key_string, std::unique_ptr<base::Value> value_dict,
    std::string worker_key_string) {
  base::Value* options_name_value = value_dict->FindKeyOfType(
      kSettingsOptionsNameKey, base::Value::Type::STRING);
  if (options_name_value == nullptr) return false;
  ServiceWorkerObject::Options options(options_name_value->GetString(),
                                       options_.web_settings,
                                       options_.network_module, registration);
  options.web_options.platform_info = options_.platform_info;
  options.web_options.service_worker_context = options_.service_worker_context;
  scoped_refptr<ServiceWorkerObject> worker(new ServiceWorkerObject(options));

  base::Value* script_url_value = value_dict->FindKeyOfType(
      kSettingsScriptUrlKey, base::Value::Type::STRING);
  if (script_url_value == nullptr) return false;
  worker->set_script_url(GURL(script_url_value->GetString()));

  base::Value* skip_waiting_value = value_dict->FindKeyOfType(
      kSettingsSkipWaitingKey, base::Value::Type::BOOLEAN);
  if (skip_waiting_value == nullptr) return false;
  if (skip_waiting_value->GetBool()) worker->set_skip_waiting();

  base::Value* classic_scripts_imported_value = value_dict->FindKeyOfType(
      kSettingsClassicScriptsImportedKey, base::Value::Type::BOOLEAN);
  if (classic_scripts_imported_value == nullptr) return false;
  if (classic_scripts_imported_value->GetBool())
    worker->set_classic_scripts_imported();

  worker->set_start_status(nullptr);

  base::Value* used_scripts_value = value_dict->FindKeyOfType(
      kSettingsSetOfUsedScriptsKey, base::Value::Type::LIST);
  if (used_scripts_value == nullptr) return false;
  std::vector<base::Value> used_scripts_list = used_scripts_value->TakeList();
  for (int i = 0; i < used_scripts_list.size(); i++) {
    auto script_value = std::move(used_scripts_list[i]);
    if (script_value.is_string()) {
      worker->AppendToSetOfUsedScripts(GURL(script_value.GetString()));
    }
  }
  base::Value* script_urls_value = value_dict->FindKeyOfType(
      kSettingsScriptResourceMapScriptUrlsKey, base::Value::Type::LIST);
  if (script_urls_value == nullptr) return false;
  std::vector<base::Value> script_urls_list = script_urls_value->TakeList();
  ScriptResourceMap script_resource_map;
  for (int i = 0; i < script_urls_list.size(); i++) {
    auto script_url_value = std::move(script_urls_list[i]);
    if (script_url_value.is_string()) {
      auto script_url_string = script_url_value.GetString();
      auto script_url = GURL(script_url_string);
      std::unique_ptr<std::vector<uint8_t>> data =
          cobalt::cache::Cache::GetInstance()->Retrieve(
              network::disk_cache::ResourceType::kServiceWorkerScript,
              web::cache_utils::GetKey(key_string + script_url_string));
      if (data == nullptr) {
        return false;
      }
      auto script_resource = ScriptResource(std::make_unique<std::string>(
          std::string(data->begin(), data->end())));
      if (script_url == worker->script_url()) {
        // Get the persistent headers for the ServiceWorkerObject script_url_.
        // This is used in ServiceWorkerObject::Initialize().
        base::Value* raw_header_value = value_dict->FindKeyOfType(
            kSettingsRawHeadersKey, base::Value::Type::STRING);
        if (raw_header_value == nullptr) return false;
        const scoped_refptr<net::HttpResponseHeaders> headers =
            scoped_refptr<net::HttpResponseHeaders>(
                new net::HttpResponseHeaders(raw_header_value->GetString()));
        script_resource.headers = headers;
      }
      auto result = script_resource_map.insert(
          std::make_pair(script_url, std::move(script_resource)));
      DCHECK(result.second);
    }
  }
  if (script_resource_map.size() == 0) {
    return false;
  }
  worker->set_script_resource_map(std::move(script_resource_map));

  registration->set_waiting_worker(worker);

  return true;
}

void ServiceWorkerPersistentSettings::
    WriteServiceWorkerRegistrationObjectSettings(
        RegistrationMapKey key,
        scoped_refptr<ServiceWorkerRegistrationObject> registration) {
  auto key_string = key.first.GetURL().spec() + key.second;
  base::flat_map<std::string, std::unique_ptr<base::Value>> dict;

  // https://w3c.github.io/ServiceWorker/#user-agent-shutdown
  // An installing worker does not persist, but is discarded.
  auto waiting_worker = registration->waiting_worker();
  auto active_worker = registration->active_worker();

  if (waiting_worker == nullptr && active_worker == nullptr) {
    // If the installing worker was the only service worker for the service
    // worker registration, the service worker registration is discarded.
    RemoveServiceWorkerRegistrationObjectSettings(key);
    return;
  }

  if (waiting_worker) {
    // A waiting worker promotes to an active worker. This will be handled
    // upon restart.
    dict.try_emplace(
        kSettingsWaitingWorkerKey,
        WriteServiceWorkerObjectSettings(key_string, waiting_worker));
  } else {
    dict.try_emplace(kSettingsActiveWorkerKey, WriteServiceWorkerObjectSettings(
                                                   key_string, active_worker));
  }

  // Add key_string to the registered keys and write to persistent settings.
  key_set_.insert(key_string);
  std::vector<base::Value> key_list;
  for (auto& key : key_set_) {
    key_list.emplace_back(key);
  }
  persistent_settings_->SetPersistentSetting(
      kSettingsKeyList, std::make_unique<base::Value>(std::move(key_list)));

  // Persist ServiceWorkerRegistrationObject's fields.
  dict.try_emplace(kSettingsStorageKeyKey,
                   std::make_unique<base::Value>(
                       registration->storage_key().GetURL().spec()));

  dict.try_emplace(kSettingsScopeStringKey,
                   std::make_unique<base::Value>(key.second));

  dict.try_emplace(kSettingsScopeUrlKey, std::make_unique<base::Value>(
                                             registration->scope_url().spec()));

  dict.try_emplace(
      kSettingsUpdateViaCacheModeKey,
      std::make_unique<base::Value>(registration->update_via_cache_mode()));

  dict.try_emplace(kSettingsLastUpdateCheckTimeKey,
                   std::make_unique<base::Value>(
                       std::to_string(registration->last_update_check_time()
                                          .ToDeltaSinceWindowsEpoch()
                                          .InMicroseconds())));

  persistent_settings_->SetPersistentSetting(
      key_string, std::make_unique<base::Value>(dict));
}

std::unique_ptr<base::Value>
ServiceWorkerPersistentSettings::WriteServiceWorkerObjectSettings(
    std::string registration_key_string,
    const scoped_refptr<ServiceWorkerObject>& service_worker_object) {
  base::flat_map<std::string, std::unique_ptr<base::Value>> dict;
  DCHECK(service_worker_object);
  dict.try_emplace(
      kSettingsOptionsNameKey,
      std::make_unique<base::Value>(service_worker_object->options_name()));

  dict.try_emplace(kSettingsScriptUrlKey,
                   std::make_unique<base::Value>(
                       service_worker_object->script_url().spec()));

  dict.try_emplace(
      kSettingsSkipWaitingKey,
      std::make_unique<base::Value>(service_worker_object->skip_waiting()));

  dict.try_emplace(kSettingsClassicScriptsImportedKey,
                   std::make_unique<base::Value>(
                       service_worker_object->classic_scripts_imported()));

  // Persist set_of_used_scripts as a List.
  base::Value set_of_used_scripts_value(base::Value::Type::LIST);
  for (auto script_url : service_worker_object->set_of_used_scripts()) {
    set_of_used_scripts_value.GetList().push_back(
        base::Value(script_url.spec()));
  }
  dict.try_emplace(
      kSettingsSetOfUsedScriptsKey,
      std::make_unique<base::Value>(std::move(set_of_used_scripts_value)));

  // Persist the script_resource_map script urls as a List.
  base::Value script_urls_value(base::Value::Type::LIST);
  for (auto const& script_resource :
       service_worker_object->script_resource_map()) {
    std::string script_url_string = script_resource.first.spec();
    script_urls_value.GetList().push_back(base::Value(script_url_string));
    // Use Cache::Store to persist the script resource.
    std::string resource = *(script_resource.second.content.get());
    std::vector<uint8_t> data(resource.begin(), resource.end());
    cobalt::cache::Cache::GetInstance()->Store(
        network::disk_cache::ResourceType::kServiceWorkerScript,
        web::cache_utils::GetKey(registration_key_string + script_url_string),
        data,
        /* metadata */ base::nullopt);

    if (script_url_string == service_worker_object->script_url().spec()) {
      // Persist the raw headers from the ServiceWorkerObject script_url_
      // ScriptResource headers.
      dict.try_emplace(kSettingsRawHeadersKey,
                       std::make_unique<base::Value>(
                           script_resource.second.headers->raw_headers()));
    }
  }
  dict.try_emplace(kSettingsScriptResourceMapScriptUrlsKey,
                   std::make_unique<base::Value>(std::move(script_urls_value)));

  return std::move(std::make_unique<base::Value>(dict));
}

void ServiceWorkerPersistentSettings::
    RemoveServiceWorkerRegistrationObjectSettings(RegistrationMapKey key) {
  auto key_string = key.first.GetURL().spec() + key.second;

  if (key_set_.find(key_string) == key_set_.end()) {
    // The key does not exist in PersistentSettings.
    return;
  }

  // Remove the worker script_resource_map from the Cache.
  RemoveServiceWorkerObjectSettings(key_string);

  // Remove registration key string.
  key_set_.erase(key_string);
  std::vector<base::Value> key_list;
  for (auto& key : key_set_) {
    key_list.emplace_back(key);
  }
  persistent_settings_->SetPersistentSetting(
      kSettingsKeyList, std::make_unique<base::Value>(std::move(key_list)));

  // Remove the registration dictionary.
  persistent_settings_->RemovePersistentSetting(key_string);
}

void ServiceWorkerPersistentSettings::RemoveServiceWorkerObjectSettings(
    std::string key_string) {
  auto dict =
      persistent_settings_->GetPersistentSettingAsDictionary(key_string);
  if (dict.empty()) return;
  std::vector<std::string> worker_keys{kSettingsWaitingWorkerKey,
                                       kSettingsActiveWorkerKey};
  for (std::string worker_key : worker_keys) {
    if (!CheckPersistentValue(key_string, worker_key, dict,
                              base::Value::Type::DICTIONARY))
      continue;
    auto worker_dict = std::move(dict[worker_key]);
    base::Value* script_urls_value = worker_dict->FindKeyOfType(
        kSettingsScriptResourceMapScriptUrlsKey, base::Value::Type::LIST);
    if (script_urls_value == nullptr) return;
    std::vector<base::Value> script_urls_list = script_urls_value->TakeList();

    for (int i = 0; i < script_urls_list.size(); i++) {
      auto script_url_value = std::move(script_urls_list[i]);
      if (script_url_value.is_string()) {
        auto script_url_string = script_url_value.GetString();
        cobalt::cache::Cache::GetInstance()->Delete(
            network::disk_cache::ResourceType::kServiceWorkerScript,
            web::cache_utils::GetKey(key_string + script_url_string));
      }
    }
  }
}

void ServiceWorkerPersistentSettings::RemoveAll() {
  for (auto& key : key_set_) {
    persistent_settings_->RemovePersistentSetting(key);
  }
}

void ServiceWorkerPersistentSettings::DeleteAll(base::OnceClosure closure) {
  persistent_settings_->DeletePersistentSettings(std::move(closure));
}

}  // namespace worker
}  // namespace cobalt
