// Copyright 2017 The Fuchsia 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 "helpers.h"

#include <endian.h>

#include <unordered_set>

#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/common/uuid.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/advertising_data.h"
#include "src/connectivity/bluetooth/core/bt-host/gap/discovery_filter.h"
#include "src/lib/fxl/strings/string_number_conversions.h"

using fuchsia::bluetooth::Bool;
using fuchsia::bluetooth::Error;
using fuchsia::bluetooth::ErrorCode;
using fuchsia::bluetooth::Int8;
using fuchsia::bluetooth::Status;

namespace fble = fuchsia::bluetooth::le;
namespace fctrl = fuchsia::bluetooth::control;
namespace fhost = fuchsia::bluetooth::host;

namespace bthost {
namespace fidl_helpers {
namespace {

fctrl::TechnologyType TechnologyTypeToFidl(bt::gap::TechnologyType type) {
  switch (type) {
    case bt::gap::TechnologyType::kLowEnergy:
      return fctrl::TechnologyType::LOW_ENERGY;
    case bt::gap::TechnologyType::kClassic:
      return fctrl::TechnologyType::CLASSIC;
    case bt::gap::TechnologyType::kDualMode:
      return fctrl::TechnologyType::DUAL_MODE;
    default:
      ZX_PANIC("invalid technology type: %u", static_cast<unsigned int>(type));
      break;
  }

  // This should never execute.
  return fctrl::TechnologyType::DUAL_MODE;
}

bt::sm::SecurityProperties SecurityPropsFromFidl(
    const fhost::SecurityProperties& sec_prop) {
  auto level = bt::sm::SecurityLevel::kEncrypted;
  if (sec_prop.authenticated) {
    level = bt::sm::SecurityLevel::kAuthenticated;
  }
  return bt::sm::SecurityProperties(level, sec_prop.encryption_key_size,
                                    sec_prop.secure_connections);
}

fhost::SecurityProperties SecurityPropsToFidl(
    const bt::sm::SecurityProperties& sec_prop) {
  fhost::SecurityProperties result;
  result.authenticated = sec_prop.authenticated();
  result.secure_connections = sec_prop.secure_connections();
  result.encryption_key_size = sec_prop.enc_key_size();
  return result;
}

bt::DeviceAddress::Type BondingAddrTypeFromFidl(
    const fhost::AddressType& type) {
  switch (type) {
    case fhost::AddressType::LE_RANDOM:
      return bt::DeviceAddress::Type::kLERandom;
    case fhost::AddressType::LE_PUBLIC:
      return bt::DeviceAddress::Type::kLEPublic;
    case fhost::AddressType::BREDR:
      return bt::DeviceAddress::Type::kBREDR;
    default:
      ZX_PANIC("invalid address type: %u", static_cast<unsigned int>(type));
      break;
  }
  return bt::DeviceAddress::Type::kBREDR;
}

fhost::AddressType BondingAddrTypeToFidl(bt::DeviceAddress::Type type) {
  switch (type) {
    case bt::DeviceAddress::Type::kLERandom:
      return fhost::AddressType::LE_RANDOM;
    case bt::DeviceAddress::Type::kLEPublic:
      return fhost::AddressType::LE_PUBLIC;
    case bt::DeviceAddress::Type::kBREDR:
      return fhost::AddressType::BREDR;
    default:
      // Anonymous is not a valid address type to use for bonding, so we treat
      // that as a programming error.
      ZX_PANIC("invalid address type for bonding: %u",
               static_cast<unsigned int>(type));
      break;
  }
  return fhost::AddressType::BREDR;
}

bt::sm::LTK LtkFromFidl(const fhost::LTK& ltk) {
  return bt::sm::LTK(SecurityPropsFromFidl(ltk.key.security_properties),
                     bt::hci::LinkKey(ltk.key.value, ltk.rand, ltk.ediv));
}

fhost::LTK LtkToFidl(const bt::sm::LTK& ltk) {
  fhost::LTK result;
  result.key.security_properties = SecurityPropsToFidl(ltk.security());
  result.key.value = ltk.key().value();

  // TODO(armansito): Remove this field since its already captured in security
  // properties.
  result.key_size = ltk.security().enc_key_size();
  result.rand = ltk.key().rand();
  result.ediv = ltk.key().ediv();
  return result;
}

bt::sm::Key KeyFromFidl(const fhost::RemoteKey& key) {
  return bt::sm::Key(SecurityPropsFromFidl(key.security_properties), key.value);
}

fhost::RemoteKey KeyToFidl(const bt::sm::Key& key) {
  fhost::RemoteKey result;
  result.security_properties = SecurityPropsToFidl(key.security());
  result.value = key.value();
  return result;
}

}  // namespace

std::optional<bt::PeerId> PeerIdFromString(const std::string& id) {
  uint64_t value;
  if (!fxl::StringToNumberWithError<decltype(value)>(id, &value,
                                                     fxl::Base::k16)) {
    return std::nullopt;
  }
  return bt::PeerId(value);
}

ErrorCode HostErrorToFidl(bt::HostError host_error) {
  switch (host_error) {
    case bt::HostError::kFailed:
      return ErrorCode::FAILED;
    case bt::HostError::kTimedOut:
      return ErrorCode::TIMED_OUT;
    case bt::HostError::kInvalidParameters:
      return ErrorCode::INVALID_ARGUMENTS;
    case bt::HostError::kCanceled:
      return ErrorCode::CANCELED;
    case bt::HostError::kInProgress:
      return ErrorCode::IN_PROGRESS;
    case bt::HostError::kNotSupported:
      return ErrorCode::NOT_SUPPORTED;
    case bt::HostError::kNotFound:
      return ErrorCode::NOT_FOUND;
    case bt::HostError::kProtocolError:
      return ErrorCode::PROTOCOL_ERROR;
    default:
      break;
  }

  return ErrorCode::FAILED;
}

Status NewFidlError(ErrorCode error_code, std::string description) {
  Status status;
  status.error = Error::New();
  status.error->error_code = error_code;
  status.error->description = description;
  return status;
}

bt::sm::IOCapability IoCapabilityFromFidl(fctrl::InputCapabilityType input,
                                          fctrl::OutputCapabilityType output) {
  if (input == fctrl::InputCapabilityType::NONE &&
      output == fctrl::OutputCapabilityType::NONE) {
    return bt::sm::IOCapability::kNoInputNoOutput;
  } else if (input == fctrl::InputCapabilityType::KEYBOARD &&
             output == fctrl::OutputCapabilityType::DISPLAY) {
    return bt::sm::IOCapability::kKeyboardDisplay;
  } else if (input == fctrl::InputCapabilityType::KEYBOARD &&
             output == fctrl::OutputCapabilityType::NONE) {
    return bt::sm::IOCapability::kKeyboardOnly;
  } else if (input == fctrl::InputCapabilityType::NONE &&
             output == fctrl::OutputCapabilityType::DISPLAY) {
    return bt::sm::IOCapability::kDisplayOnly;
  } else if (input == fctrl::InputCapabilityType::CONFIRMATION &&
             output == fctrl::OutputCapabilityType::DISPLAY) {
    return bt::sm::IOCapability::kDisplayYesNo;
  }
  return bt::sm::IOCapability::kNoInputNoOutput;
}

bt::sm::PairingData PairingDataFromFidl(const fhost::LEData& data) {
  bt::sm::PairingData result;
  result.identity_address = bt::DeviceAddress(
      BondingAddrTypeFromFidl(data.address_type), data.address);
  if (data.ltk) {
    result.ltk = LtkFromFidl(*data.ltk);
  }
  if (data.irk) {
    result.irk = KeyFromFidl(*data.irk);
  }
  if (data.csrk) {
    result.csrk = KeyFromFidl(*data.csrk);
  }
  return result;
}

bt::UInt128 LocalKeyFromFidl(const fhost::LocalKey& key) { return key.value; }

std::optional<bt::sm::LTK> BrEdrKeyFromFidl(const fhost::BREDRData& data) {
  if (data.link_key) {
    return LtkFromFidl(*data.link_key);
  }
  return std::nullopt;
}

fctrl::AdapterInfo NewAdapterInfo(const bt::gap::Adapter& adapter) {
  fctrl::AdapterInfo adapter_info;
  adapter_info.identifier = adapter.identifier().ToString();
  adapter_info.technology = TechnologyTypeToFidl(adapter.state().type());
  adapter_info.address = adapter.state().controller_address().ToString();

  adapter_info.state = fctrl::AdapterState::New();
  adapter_info.state->local_name = adapter.state().local_name();
  adapter_info.state->discoverable = Bool::New();
  adapter_info.state->discoverable->value = false;
  adapter_info.state->discovering = Bool::New();
  adapter_info.state->discovering->value = adapter.IsDiscovering();

  // TODO(armansito): Populate |local_service_uuids| as well.

  return adapter_info;
}

fctrl::RemoteDevice NewRemoteDevice(const bt::gap::Peer& peer) {
  fctrl::RemoteDevice fidl_device;
  fidl_device.identifier = peer.identifier().ToString();
  fidl_device.address = peer.address().value().ToString();
  fidl_device.technology = TechnologyTypeToFidl(peer.technology());
  fidl_device.connected = peer.connected();
  fidl_device.bonded = peer.bonded();

  // Set default value for device appearance.
  fidl_device.appearance = fctrl::Appearance::UNKNOWN;

  // |service_uuids| is not a nullable field, so we need to assign something
  // to it.
  fidl_device.service_uuids.resize(0);

  if (peer.rssi() != bt::hci::kRSSIInvalid) {
    fidl_device.rssi = Int8::New();
    fidl_device.rssi->value = peer.rssi();
  }

  if (peer.name()) {
    fidl_device.name = *peer.name();
  }

  if (peer.le()) {
    bt::gap::AdvertisingData adv_data;

    if (!bt::gap::AdvertisingData::FromBytes(peer.le()->advertising_data(),
                                             &adv_data)) {
      return fidl_device;
    }

    for (const auto& uuid : adv_data.service_uuids()) {
      fidl_device.service_uuids.push_back(uuid.ToString());
    }
    if (adv_data.appearance()) {
      fidl_device.appearance =
          static_cast<fctrl::Appearance>(le16toh(*adv_data.appearance()));
    }
    if (adv_data.tx_power()) {
      auto fidl_tx_power = Int8::New();
      fidl_tx_power->value = *adv_data.tx_power();
      fidl_device.tx_power = std::move(fidl_tx_power);
    }
  }

  return fidl_device;
}

fctrl::RemoteDevicePtr NewRemoteDevicePtr(const bt::gap::Peer& peer) {
  auto fidl_device = fctrl::RemoteDevice::New();
  *fidl_device = NewRemoteDevice(peer);
  return fidl_device;
}

fhost::BondingData NewBondingData(const bt::gap::Adapter& adapter,
                                  const bt::gap::Peer& peer) {
  fhost::BondingData out_data;
  out_data.identifier = peer.identifier().ToString();
  out_data.local_address = adapter.state().controller_address().ToString();

  if (peer.name()) {
    out_data.name = *peer.name();
  }

  // Store LE data.
  if (peer.le() && peer.le()->bond_data()) {
    out_data.le = fhost::LEData::New();

    const auto& le_data = *peer.le()->bond_data();
    const auto& identity =
        le_data.identity_address ? *le_data.identity_address : peer.address();
    out_data.le->address = identity.value().ToString();
    out_data.le->address_type = BondingAddrTypeToFidl(identity.type());

    // TODO(armansito): Populate the preferred connection parameters here.

    // TODO(armansito): Populate with discovered GATT services. We initialize
    // this as empty as |services| is not nullable.
    out_data.le->services.resize(0);

    if (le_data.ltk) {
      out_data.le->ltk = fhost::LTK::New();
      *out_data.le->ltk = LtkToFidl(*le_data.ltk);
    }
    if (le_data.irk) {
      out_data.le->irk = fhost::RemoteKey::New();
      *out_data.le->irk = KeyToFidl(*le_data.irk);
    }
    if (le_data.csrk) {
      out_data.le->csrk = fhost::RemoteKey::New();
      *out_data.le->csrk = KeyToFidl(*le_data.csrk);
    }
  }

  // Store BR/EDR data.
  if (peer.bredr() && peer.bredr()->link_key()) {
    out_data.bredr = fhost::BREDRData::New();

    out_data.bredr->address = peer.bredr()->address().value().ToString();

    // TODO(BT-669): Populate with history of role switches.
    out_data.bredr->piconet_leader = false;

    // TODO(BT-670): Populate with discovered SDP services.
    out_data.bredr->services.resize(0);

    if (peer.bredr()->link_key()) {
      out_data.bredr->link_key = fhost::LTK::New();
      *out_data.bredr->link_key = LtkToFidl(*peer.bredr()->link_key());
    }
  }

  return out_data;
}

fble::RemoteDevicePtr NewLERemoteDevice(const bt::gap::Peer& peer) {
  bt::gap::AdvertisingData ad;
  if (!peer.le()) {
    return nullptr;
  }

  const auto& le = *peer.le();
  auto fidl_device = fble::RemoteDevice::New();
  fidl_device->identifier = peer.identifier().ToString();
  fidl_device->connectable = peer.connectable();

  // Initialize advertising data only if its non-empty.
  if (le.advertising_data().size() != 0u) {
    bt::gap::AdvertisingData ad;
    if (!bt::gap::AdvertisingData::FromBytes(le.advertising_data(), &ad)) {
      return nullptr;
    }
    fidl_device->advertising_data = ad.AsLEAdvertisingData();
  }

  if (peer.rssi() != bt::hci::kRSSIInvalid) {
    fidl_device->rssi = Int8::New();
    fidl_device->rssi->value = peer.rssi();
  }

  return fidl_device;
}

bool IsScanFilterValid(const fble::ScanFilter& fidl_filter) {
  // |service_uuids| is the only field that can potentially contain invalid
  // data, since they are represented as strings.
  if (!fidl_filter.service_uuids)
    return true;

  for (const auto& uuid_str : *fidl_filter.service_uuids) {
    if (!bt::IsStringValidUuid(uuid_str))
      return false;
  }

  return true;
}

bool PopulateDiscoveryFilter(const fble::ScanFilter& fidl_filter,
                             bt::gap::DiscoveryFilter* out_filter) {
  ZX_DEBUG_ASSERT(out_filter);

  if (fidl_filter.service_uuids) {
    std::vector<bt::UUID> uuids;
    for (const auto& uuid_str : *fidl_filter.service_uuids) {
      bt::UUID uuid;
      if (!bt::StringToUuid(uuid_str, &uuid)) {
        bt_log(TRACE, "bt-host", "invalid parameters given to scan filter");
        return false;
      }
      uuids.push_back(uuid);
    }

    if (!uuids.empty())
      out_filter->set_service_uuids(uuids);
  }

  if (fidl_filter.connectable) {
    out_filter->set_connectable(fidl_filter.connectable->value);
  }

  if (fidl_filter.manufacturer_identifier) {
    out_filter->set_manufacturer_code(
        fidl_filter.manufacturer_identifier->value);
  }

  if (fidl_filter.name_substring && !fidl_filter.name_substring.get().empty()) {
    out_filter->set_name_substring(fidl_filter.name_substring.get());
  }

  if (fidl_filter.max_path_loss) {
    out_filter->set_pathloss(fidl_filter.max_path_loss->value);
  }

  return true;
}

}  // namespace fidl_helpers
}  // namespace bthost

// static
fidl::VectorPtr<uint8_t>
fidl::TypeConverter<fidl::VectorPtr<uint8_t>, bt::ByteBuffer>::Convert(
    const bt::ByteBuffer& from) {
  auto to = fidl::VectorPtr<uint8_t>::New(from.size());
  bt::MutableBufferView view(to->data(), to->size());
  view.Write(from);
  return to;
}
