// Copyright 2021 Google LLC
//
// 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
//
//     https://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 "platform/impl/windows/wifi_lan.h"

// Windows headers
#include <windows.h>

// Standard C/C++ headers
#include <codecvt>
#include <locale>
#include <string>

// ABSL headers
#include "absl/strings/str_format.h"

// Nearby connections headers
#include "platform/base/cancellation_flag_listener.h"
#include "platform/impl/windows/utils.h"
#include "platform/public/logging.h"
#include "platform/public/mutex_lock.h"

namespace location {
namespace nearby {
namespace windows {

bool WifiLanMedium::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
  absl::MutexLock lock(&mutex_);

  if (!IsAccepting()) {
    NEARBY_LOGS(WARNING)
        << "cannot start advertising without accepting connetions.";
    return false;
  }

  if (IsAdvertising()) {
    NEARBY_LOGS(WARNING)
        << "cannot start advertising again when it is running.";
    return false;
  }

  if (nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data()).empty()) {
    NEARBY_LOGS(ERROR) << "cannot start advertising without endpoint info.";
    return false;
  }

  if (nsd_service_info.GetServiceName().empty()) {
    NEARBY_LOGS(ERROR) << "cannot start advertising without service name.";
    return false;
  }

  std::string instance_name = absl::StrFormat(
      MDNS_INSTANCE_NAME_FORMAT.data(), nsd_service_info.GetServiceName(),
      nsd_service_info.GetServiceType());

  NEARBY_LOGS(INFO) << "mDNS instance name is " << instance_name;

  dnssd_service_instance_ = DnssdServiceInstance{
      string_to_wstring(instance_name),
      nullptr,  // let windows use default computer's local name
      (uint16)nsd_service_info.GetPort()};

  // Add TextRecords from NsdServiceInfo
  auto text_attributes = dnssd_service_instance_.TextAttributes();

  auto text_records = nsd_service_info.GetTxtRecords();
  auto it = text_records.begin();
  while (it != text_records.end()) {
    text_attributes.Insert(string_to_wstring(it->first),
                           string_to_wstring(it->second));
    it++;
  }

  dnssd_regirstraion_result_ = dnssd_service_instance_
                                   .RegisterStreamSocketListenerAsync(
                                       server_socket_ptr_->GetSocketListener())
                                   .get();

  if (dnssd_regirstraion_result_.HasInstanceNameChanged()) {
    NEARBY_LOGS(WARNING) << "advertising instance name was changed due to have "
                            "same name instance was running.";
    // stop the service and return false
    StopAdvertising(nsd_service_info);
    return false;
  }

  if (dnssd_regirstraion_result_.Status() == DnssdRegistrationStatus::Success) {
    NEARBY_LOGS(INFO) << "started to advertising.";
    medium_status_ |= MEDIUM_STATUS_ADVERTISING;
    return true;
  }

  // Clean up
  NEARBY_LOGS(ERROR)
      << "failed to start advertising due to registration failure.";
  dnssd_service_instance_ = nullptr;
  dnssd_regirstraion_result_ = nullptr;
  return false;
}

// Win32 call only can use globel function or static method in class
void WifiLanMedium::Advertising_StopCompleted(DWORD Status, PVOID pQueryContext,
                                              PDNS_SERVICE_INSTANCE pInstance) {
  NEARBY_LOGS(INFO) << "unregister with status=" << Status;
  try {
    WifiLanMedium* medium = static_cast<WifiLanMedium*>(pQueryContext);
    medium->NotifyDnsServiceUnregistered(Status);
  } catch (...) {
    NEARBY_LOGS(ERROR) << "failed to notify the stop of DNS service instance."
                       << Status;
  }
}

void WifiLanMedium::NotifyDnsServiceUnregistered(DWORD status) {
  if (dns_service_stop_latch_.get() != nullptr) {
    dns_service_stop_status_ = status;
    dns_service_stop_latch_.get()->CountDown();
  }
}

bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
  // Need to use Win32 API to deregister the Dnssd instance
  if (!IsAdvertising()) {
    NEARBY_LOGS(WARNING)
        << "Cannot stop advertising because no advertising is running.";
    return false;
  }

  // Init DNS service instance
  std::string instance_name = absl::StrFormat(
      MDNS_INSTANCE_NAME_FORMAT.data(), nsd_service_info.GetServiceName(),
      nsd_service_info.GetServiceType());
  int port = nsd_service_info.GetPort();
  dns_service_instance_name_ =
      std::make_unique<std::wstring>(string_to_wstring(instance_name));

  dns_service_instance_.pszInstanceName =
      (LPWSTR)dns_service_instance_name_->c_str();
  dns_service_instance_.pszHostName = (LPWSTR)MDNS_HOST_NAME.data();
  dns_service_instance_.wPort = port;

  // Init DNS service register request
  dns_service_register_request_.Version = DNS_QUERY_REQUEST_VERSION1;
  dns_service_register_request_.InterfaceIndex =
      0;  // all interfaces will be considered
  dns_service_register_request_.unicastEnabled = false;
  dns_service_register_request_.hCredentials = NULL;
  dns_service_register_request_.pServiceInstance = &dns_service_instance_;
  dns_service_register_request_.pQueryContext = this;  // callback use it
  dns_service_register_request_.pRegisterCompletionCallback =
      WifiLanMedium::Advertising_StopCompleted;

  dns_service_stop_latch_ = std::make_unique<CountDownLatch>(1);
  DWORD status = DnsServiceDeRegister(&dns_service_register_request_, nullptr);

  if (status != DNS_REQUEST_PENDING) {
    NEARBY_LOGS(ERROR) << "failed to stop mDNS advertising for service type ="
                       << nsd_service_info.GetServiceType();
    return false;
  }

  // Wait for stop finish
  dns_service_stop_latch_.get()->Await();
  dns_service_stop_latch_ = nullptr;
  if (dns_service_stop_status_ != 0) {
    NEARBY_LOGS(INFO) << "failed to stop mDNS advertising for service type ="
                      << nsd_service_info.GetServiceType();
    return false;
  }

  NEARBY_LOGS(INFO) << "succeeded to stop mDNS advertising for service type ="
                    << nsd_service_info.GetServiceType();
  medium_status_ &= (~MEDIUM_STATUS_ADVERTISING);
  return true;
}

// Returns true once the WifiLan discovery has been initiated.
bool WifiLanMedium::StartDiscovery(const std::string& service_type,
                                   DiscoveredServiceCallback callback) {
  if (IsDiscovering()) {
    NEARBY_LOGS(WARNING) << "discovery already running for service type ="
                         << service_type;
    return false;
  }

  std::string selector =
      absl::StrFormat(MDNS_DEVICE_SELECTOR_FORMAT.data(), service_type);

  std::vector<winrt::hstring> requestedProperties{
      L"System.Devices.IpAddress",
      L"System.Devices.Dnssd.HostName",
      L"System.Devices.Dnssd.InstanceName",
      L"System.Devices.Dnssd.PortNumber",
      L"System.Devices.Dnssd.ServiceName",
      L"System.Devices.Dnssd.TextAttributes"};

  device_watcher_ = DeviceInformation::CreateWatcher(
      string_to_wstring(selector), requestedProperties,
      DeviceInformationKind::AssociationEndpointService);

  device_watcher_added_event_token =
      device_watcher_.Added({this, &WifiLanMedium::Watcher_DeviceAdded});
  device_watcher_updated_event_token =
      device_watcher_.Updated({this, &WifiLanMedium::Watcher_DeviceUpdated});
  device_watcher_removed_event_token =
      device_watcher_.Removed({this, &WifiLanMedium::Watcher_DeviceRemoved});

  device_watcher_.Start();
  discovered_service_callback_ = std::move(callback);
  medium_status_ |= MEDIUM_STATUS_DISCOVERING;

  NEARBY_LOGS(INFO) << "started to discovery.";

  return true;
}

// Returns true once WifiLan discovery for service_id is well and truly
// stopped; after this returns, there must be no more invocations of the
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
bool WifiLanMedium::StopDiscovery(const std::string& service_type) {
  if (!IsDiscovering()) {
    NEARBY_LOGS(WARNING) << "no discovering service to stop.";
    return false;
  }
  device_watcher_.Stop();
  device_watcher_.Added(device_watcher_added_event_token);
  device_watcher_.Updated(device_watcher_updated_event_token);
  device_watcher_.Removed(device_watcher_removed_event_token);
  medium_status_ &= (~MEDIUM_STATUS_DISCOVERING);
  device_watcher_ = nullptr;
  return true;
}

std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
    const NsdServiceInfo& remote_service_info,
    CancellationFlag* cancellation_flag) {
  NEARBY_LOGS(ERROR)
      << "connect to service by NSD service info. service type is "
      << remote_service_info.GetServiceType();

  return ConnectToService(remote_service_info.GetIPAddress(),
                          remote_service_info.GetPort(), cancellation_flag);
}

std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
    const std::string& ip_address, int port,
    CancellationFlag* cancellation_flag) {
  if (ip_address.empty() || port == 0) {
    NEARBY_LOGS(ERROR) << "no valid service address and port to connect.";
    return nullptr;
  }

  HostName host_name{string_to_wstring(ip_address)};
  winrt::hstring service_name{winrt::to_hstring(port)};

  StreamSocket socket{};

  // setup cancel listener
  if (cancellation_flag != nullptr) {
    if (cancellation_flag->Cancelled()) {
      NEARBY_LOGS(INFO) << "connect has been cancelled to service "
                        << ip_address << ":" << port;
      return nullptr;
    }

    location::nearby::CancellationFlagListener cancellationFlagListener(
        cancellation_flag, [socket]() { socket.CancelIOAsync().get(); });
  }

  // connection to the service
  try {
    socket.ConnectAsync(host_name, service_name).get();
    // connected need to keep connection

    std::unique_ptr<WifiLanSocket> wifi_lan_socket =
        std::make_unique<WifiLanSocket>(socket);

    NEARBY_LOGS(INFO) << "connected to remote service " << ip_address << ":"
                      << port;
    return wifi_lan_socket;
  } catch (...) {
    NEARBY_LOGS(ERROR) << "failed to connect remote service " << ip_address
                       << ":" << port;
  }

  return nullptr;
}

std::unique_ptr<api::WifiLanServerSocket> WifiLanMedium::ListenForService(
    int port) {
  absl::MutexLock lock(&mutex_);

  // check current status
  if (IsAccepting()) {
    NEARBY_LOGS(WARNING) << "accepting connections already started on port "
                         << server_socket_ptr_->GetPort();
    return nullptr;
  }

  std::unique_ptr<WifiLanServerSocket> server_socket =
      std::make_unique<WifiLanServerSocket>(port);
  server_socket_ptr_ = server_socket.get();

  server_socket->SetCloseNotifier([this]() {
    absl::MutexLock lock(&mutex_);
    NEARBY_LOGS(INFO) << "server socket was closed on port "
                      << server_socket_ptr_->GetPort();
    medium_status_ &= (~MEDIUM_STATUS_ACCEPTING);
    server_socket_ptr_ = nullptr;
  });

  if (server_socket->listen()) {
    medium_status_ |= MEDIUM_STATUS_ACCEPTING;
    NEARBY_LOGS(INFO) << "started to listen serive on port " << port;
    return server_socket;
  }

  NEARBY_LOGS(ERROR) << "Failed to listen service on port " << port;

  return nullptr;
}

NsdServiceInfo WifiLanMedium::GetNsdServiceInformation(
    IMapView<winrt::hstring, IInspectable> properties) {
  NsdServiceInfo nsd_service_info{};

  // Service name information
  IInspectable inspectable =
      properties.TryLookup(L"System.Devices.Dnssd.InstanceName");
  if (inspectable == nullptr) {
    NEARBY_LOGS(WARNING)
        << "no service name information in device information.";
    return nsd_service_info;
  }
  nsd_service_info.SetServiceName(InspectableReader::ReadString(inspectable));

  // IP Address information
  inspectable = properties.TryLookup(L"System.Devices.IPAddress");
  if (inspectable == nullptr) {
    NEARBY_LOGS(WARNING) << "no IP address information in device information.";
    return nsd_service_info;
  }

  auto ipaddresses = InspectableReader::ReadStringArray(inspectable);
  if (ipaddresses.size() == 0) {
    NEARBY_LOGS(WARNING) << "no IP address information in device information.";
    return nsd_service_info;
  }

  std::string ip_address = ipaddresses[0];

  // read IP port
  inspectable = properties.TryLookup(L"System.Devices.Dnssd.PortNumber");
  if (inspectable == nullptr) {
    NEARBY_LOGS(WARNING) << "no IP port information in device information.";
    return nsd_service_info;
  }

  int port = InspectableReader::ReadUint16(inspectable);
  nsd_service_info.SetIPAddress(ip_address);
  nsd_service_info.SetPort(port);

  // read text record
  inspectable = properties.TryLookup(L"System.Devices.Dnssd.TextAttributes");
  if (inspectable == nullptr) {
    NEARBY_LOGS(WARNING)
        << "no text attributes information in device information.";
    return nsd_service_info;
  }

  auto text_attributes = InspectableReader::ReadStringArray(inspectable);
  for (auto text_attribute : text_attributes) {
    // text attribute in format key=value
    int pos = text_attribute.find("=");
    if (pos <= 0 || pos == text_attribute.size() - 1) {
      NEARBY_LOGS(WARNING) << "found invalid text attribute " << text_attribute;
      continue;
    }

    std::string key = text_attribute.substr(0, pos);
    std::string value = text_attribute.substr(pos + 1);
    nsd_service_info.SetTxtRecord(key, value);
  }

  return nsd_service_info;
}

fire_and_forget WifiLanMedium::Watcher_DeviceAdded(
    DeviceWatcher sender, DeviceInformation deviceInfo) {
  // need to read IP address and port information from deviceInfo
  NsdServiceInfo nsd_service_info =
      GetNsdServiceInformation(deviceInfo.Properties());

  NEARBY_LOGS(INFO) << "device added for service name "
                    << nsd_service_info.GetServiceName();

  std::string endpoint =
      nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data());
  if (endpoint.empty()) {
    return fire_and_forget{};
  }

  discovered_service_callback_.service_discovered_cb(nsd_service_info);

  return fire_and_forget();
}
fire_and_forget WifiLanMedium::Watcher_DeviceUpdated(
    DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
  // TODO(b/200421481): discovery servcie callback needs to support device
  // update.
  NsdServiceInfo nsd_service_info =
      GetNsdServiceInformation(deviceInfoUpdate.Properties());
  NEARBY_LOGS(INFO) << "device updated for service name "
                    << nsd_service_info.GetServiceName();

  return fire_and_forget();
}
fire_and_forget WifiLanMedium::Watcher_DeviceRemoved(
    DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
  // need to read IP address and port information from deviceInfo
  NsdServiceInfo nsd_service_info =
      GetNsdServiceInformation(deviceInfoUpdate.Properties());

  NEARBY_LOGS(INFO) << "device removed for service name "
                    << nsd_service_info.GetServiceName();

  std::string endpoint =
      nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data());
  if (endpoint.empty()) {
    return fire_and_forget{};
  }

  discovered_service_callback_.service_lost_cb(nsd_service_info);

  return fire_and_forget();
}

std::string WifiLanMedium::GetErrorMessage(std::exception_ptr eptr) {
  try {
    if (eptr) {
      std::rethrow_exception(eptr);
    } else {
      return "";
    }
  } catch (const std::exception& e) {
    return e.what();
  }
}

}  // namespace windows
}  // namespace nearby
}  // namespace location
