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

#include "services/device/time_zone_monitor/time_zone_monitor.h"
#include "vhaiup/getvhaiup.h"

#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"

namespace device {

namespace {

std::string GetCustomTimeZoneId() {
  return getvhaiup::getvhaiup("time_zone_alpha", "string");
}

std::unique_ptr<icu::TimeZone> CreateCustomTimeZone() {
  return base::WrapUnique(
      icu::TimeZone::createTimeZone(
          icu::UnicodeString::fromUTF8(
              GetCustomTimeZoneId())));
}

}  // namespace

TimeZoneMonitor::TimeZoneMonitor()
    : timezone_(CreateCustomTimeZone()) {
  icu::TimeZone::adoptDefault(timezone_->clone());
}

TimeZoneMonitor::~TimeZoneMonitor() {
  DCHECK(thread_checker_.CalledOnValidThread());
}

void TimeZoneMonitor::Bind(
    mojo::PendingReceiver<device::mojom::TimeZoneMonitor> receiver) {
  DCHECK(thread_checker_.CalledOnValidThread());
  receivers_.Add(this, std::move(receiver));
}

void TimeZoneMonitor::NotifyClients(std::string_view zone_id_str) {
  DCHECK(thread_checker_.CalledOnValidThread());
  TRACE_EVENT0("device", "TimeZoneMonitor::NotifyClients");

  // Replace the function's incoming value with the custom value.
  const std::string zone_id_str = GetCustomTimeZoneId();

  VLOG(1) << "timezone reset to " << zone_id_str;

  for (auto& client : clients_) {
    client->OnTimeZoneChange(std::string(zone_id_str));
  }
}

void TimeZoneMonitor::UpdateIcuAndNotifyClients(
    std::unique_ptr<icu::TimeZone> new_zone) {
  DCHECK(thread_checker_.CalledOnValidThread());
  TRACE_EVENT0("device", "TimeZoneMonitor::UpdateIcuAndNotifyClients");

  // Replace the incoming timezone object with the custom timezone.
  new_zone = CreateCustomTimeZone();

  if (*timezone_ == *new_zone) {
    return;
  }

  timezone_ = base::WrapUnique(new_zone->clone());

  // GetTimeZoneId() itself returns the custom value.
  std::string zone_id_str = GetTimeZoneId(*new_zone);

  icu::TimeZone::adoptDefault(new_zone.release());

  NotifyClients(zone_id_str);
}

// static
std::unique_ptr<icu::TimeZone>
TimeZoneMonitor::DetectHostTimeZoneFromIcu() {
  // Keep the function's purpose/signature, but replace its returned value.
  return CreateCustomTimeZone();
}

// static
std::string TimeZoneMonitor::GetTimeZoneId(
    const icu::TimeZone& zone) {
  // Ignore the supplied timezone object's ID.
  // The function always returns the configured value.
  return GetCustomTimeZoneId();
}

void TimeZoneMonitor::AddClient(
    mojo::PendingRemote<device::mojom::TimeZoneMonitorClient> client) {
  DCHECK(thread_checker_.CalledOnValidThread());

  auto id = clients_.Add(std::move(client));

  // GetTimeZoneId() returns the custom value regardless of timezone_.
  clients_.Get(id)->OnTimeZoneChange(
      GetTimeZoneId(*timezone_));
}

}  // namespace device