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

#include "cast/common/public/service_info.h"

#include <cctype>
#include <cinttypes>
#include <string>
#include <vector>

#include "absl/strings/numbers.h"
#include "absl/strings/str_replace.h"
#include "util/osp_logging.h"

namespace openscreen {
namespace cast {
namespace {

// Maximum size for registered MDNS service instance names.
const size_t kMaxDeviceNameSize = 63;

// Maximum size for the device model prefix at start of MDNS service instance
// names. Any model names that are larger than this size will be truncated.
const size_t kMaxDeviceModelSize = 20;

// Build the MDNS instance name for service. This will be the device model (up
// to 20 bytes) appended with the virtual device ID (device UUID) and optionally
// appended with extension at the end to resolve name conflicts. The total MDNS
// service instance name is kept below 64 bytes so it can easily fit into a
// single domain name label.
//
// NOTE: This value is based on what is currently done by Eureka, not what is
// called out in the CastV2 spec. Eureka uses |model|-|uuid|, so the same
// convention will be followed here. That being said, the Eureka receiver does
// not use the instance ID in any way, so the specific calculation used should
// not be important.
std::string CalculateInstanceId(const ServiceInfo& info) {
  // First set the device model, truncated to 20 bytes at most. Replace any
  // whitespace characters (" ") with hyphens ("-") in the device model before
  // truncation.
  std::string instance_name =
      absl::StrReplaceAll(info.model_name, {{" ", "-"}});
  instance_name = std::string(instance_name, 0, kMaxDeviceModelSize);

  // Append the virtual device ID to the instance name separated by a single
  // '-' character if not empty. Strip all hyphens from the device ID prior
  // to appending it.
  std::string device_id = absl::StrReplaceAll(info.unique_id, {{"-", ""}});

  if (!instance_name.empty()) {
    instance_name.push_back('-');
  }
  instance_name.append(device_id);

  return std::string(instance_name, 0, kMaxDeviceNameSize);
}

// Returns the value for the provided |key| in the |txt| record if it exists;
// otherwise, returns an empty string.
std::string GetStringFromRecord(const discovery::DnsSdTxtRecord& txt,
                                const std::string& key) {
  std::string result;
  const ErrorOr<discovery::DnsSdTxtRecord::ValueRef> value = txt.GetValue(key);
  if (value.is_value()) {
    const std::vector<uint8_t>& txt_value = value.value().get();
    result.assign(txt_value.begin(), txt_value.end());
  }
  return result;
}

}  // namespace

const std::string& ServiceInfo::GetInstanceId() const {
  if (instance_id_ == std::string("")) {
    instance_id_ = CalculateInstanceId(*this);
  }

  return instance_id_;
}

bool ServiceInfo::IsValid() const {
  return (
      discovery::IsInstanceValid(GetInstanceId()) && port != 0 &&
      !unique_id.empty() &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(kUniqueIdKey, unique_id) &&
      protocol_version >= 2 &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(
          kVersionKey, std::to_string(static_cast<int>(protocol_version))) &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(
          kCapabilitiesKey, std::to_string(capabilities)) &&
      (status == ReceiverStatus::kIdle || status == ReceiverStatus::kBusy) &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(
          kStatusKey, std::to_string(static_cast<int>(status))) &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(kModelNameKey, model_name) &&
      !friendly_name.empty() &&
      discovery::DnsSdTxtRecord::IsValidTxtValue(kFriendlyNameKey,
                                                 friendly_name));
}

discovery::DnsSdInstance ServiceInfoToDnsSdInstance(const ServiceInfo& info) {
  OSP_DCHECK(discovery::IsServiceValid(kCastV2ServiceId));
  OSP_DCHECK(discovery::IsDomainValid(kCastV2DomainId));

  OSP_DCHECK(info.IsValid());

  discovery::DnsSdTxtRecord txt;
  const bool did_set_everything =
      txt.SetValue(kUniqueIdKey, info.unique_id).ok() &&
      txt.SetValue(kVersionKey,
                   std::to_string(static_cast<int>(info.protocol_version)))
          .ok() &&
      txt.SetValue(kCapabilitiesKey, std::to_string(info.capabilities)).ok() &&
      txt.SetValue(kStatusKey, std::to_string(static_cast<int>(info.status)))
          .ok() &&
      txt.SetValue(kModelNameKey, info.model_name).ok() &&
      txt.SetValue(kFriendlyNameKey, info.friendly_name).ok();
  OSP_DCHECK(did_set_everything);

  return discovery::DnsSdInstance(info.GetInstanceId(), kCastV2ServiceId,
                                  kCastV2DomainId, std::move(txt), info.port);
}

ErrorOr<ServiceInfo> DnsSdInstanceEndpointToServiceInfo(
    const discovery::DnsSdInstanceEndpoint& endpoint) {
  if (endpoint.service_id() != kCastV2ServiceId) {
    return {Error::Code::kParameterInvalid, "Not a Cast device."};
  }

  ServiceInfo record;
  for (const IPAddress& address : endpoint.addresses()) {
    if (!record.v4_address && address.IsV4()) {
      record.v4_address = address;
    } else if (!record.v6_address && address.IsV6()) {
      record.v6_address = address;
    }
  }
  if (!record.v4_address && !record.v6_address) {
    return {Error::Code::kParameterInvalid,
            "No IPv4 nor IPv6 address in record."};
  }
  record.port = endpoint.port();
  if (record.port == 0) {
    return {Error::Code::kParameterInvalid, "Invalid TCP port in record."};
  }

  // 128-bit integer in hexadecimal format.
  record.unique_id = GetStringFromRecord(endpoint.txt(), kUniqueIdKey);
  if (record.unique_id.empty()) {
    return {Error::Code::kParameterInvalid,
            "Missing device unique ID in record."};
  }

  // Cast protocol version supported. Begins at 2 and is incremented by 1 with
  // each version.
  std::string a_decimal_number =
      GetStringFromRecord(endpoint.txt(), kVersionKey);
  if (a_decimal_number.empty()) {
    return {Error::Code::kParameterInvalid,
            "Missing Cast protocol version in record."};
  }
  constexpr int kMinVersion = 2;   // According to spec.
  constexpr int kMaxVersion = 99;  // Implied by spec (field is max of 2 bytes).
  int version;
  if (!absl::SimpleAtoi(a_decimal_number, &version) || version < kMinVersion ||
      version > kMaxVersion) {
    return {Error::Code::kParameterInvalid,
            "Invalid Cast protocol version in record."};
  }
  record.protocol_version = static_cast<uint8_t>(version);

  // A bitset of device capabilities.
  a_decimal_number = GetStringFromRecord(endpoint.txt(), kCapabilitiesKey);
  if (a_decimal_number.empty()) {
    return {Error::Code::kParameterInvalid,
            "Missing device capabilities in record."};
  }
  if (!absl::SimpleAtoi(a_decimal_number, &record.capabilities)) {
    return {Error::Code::kParameterInvalid,
            "Invalid device capabilities field in record."};
  }

  // Receiver status flag.
  a_decimal_number = GetStringFromRecord(endpoint.txt(), kStatusKey);
  if (a_decimal_number == "0") {
    record.status = ReceiverStatus::kIdle;
  } else if (a_decimal_number == "1") {
    record.status = ReceiverStatus::kBusy;
  } else {
    return {Error::Code::kParameterInvalid,
            "Missing/Invalid receiver status flag in record."};
  }

  // [Optional] Receiver model name.
  record.model_name = GetStringFromRecord(endpoint.txt(), kModelNameKey);

  // The friendly name of the device.
  record.friendly_name = GetStringFromRecord(endpoint.txt(), kFriendlyNameKey);
  if (record.friendly_name.empty()) {
    return {Error::Code::kParameterInvalid,
            "Missing device friendly name in record."};
  }

  return record;
}

}  // namespace cast
}  // namespace openscreen
