// Copyright 2019 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 <fuchsia/net/mdns/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>

#include <algorithm>
#include <iostream>
#include <string>

#include "lib/fidl/cpp/type_converter.h"
#include "src/lib/fostr/fidl/fuchsia/net/formatting.h"
#include "src/lib/fostr/fidl/fuchsia/net/mdns/formatting.h"
#include "src/lib/fsl/types/type_converters.h"

const std::string kLocalArgument = "--local";
const std::string kRemoteArgument = "--remote";
const std::string kServiceName = "_mdnstest._udp.";
const std::string kInstanceName = "mdns_test_instance_name";
const uint16_t kPort = 1234;
const std::vector<std::string> kText = {"chowder", "hammock", "beanstalk"};
constexpr uint16_t kPriority = 4;
constexpr uint16_t kWeight = 5;
const std::string kRemoteHostName = "mdns-test-device-remote";
const fuchsia::net::Ipv4Address kRemoteV4Address{{192, 168, 0, 1}};
const fuchsia::net::Ipv4Address kLocalV4AddressA{{192, 168, 0, 2}};
const fuchsia::net::Ipv4Address kLocalV4AddressB{{192, 168, 0, 3}};
// const fuchsia::net::Ipv6Address kRemoteV6Address{{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//                                                  0x46, 0x07, 0x0b, 0xff, 0xfe, 0x60, 0x59,
//                                                  0x5d}};
const zx_duration_t kTimeout = ZX_SEC(60);

namespace mdns::test {

using QuitCallback = fit::function<void(int)>;

////////////////////////////////////////////////////////////////////////////////
// LocalEnd
//
// An instance of this class runs as the 'local' end of the test, which runs
// the tests.
//
// This test verifies that a service published by the remote end is properly
// discovered and that the host name of the remote end can be successfully
// resolved to an IP address.
class LocalEnd : public fuchsia::net::mdns::ServiceSubscriber {
 public:
  static std::unique_ptr<LocalEnd> Create(sys::ComponentContext* component_context,
                                          QuitCallback quit_callback) {
    return std::make_unique<LocalEnd>(component_context, std::move(quit_callback));
  }

  LocalEnd(sys::ComponentContext* component_context, QuitCallback quit_callback)
      : component_context_(component_context),
        quit_callback_(std::move(quit_callback)),
        subscriber_binding_(this) {
    subscriber_ = component_context_->svc()->Connect<fuchsia::net::mdns::Subscriber>();

    subscriber_.set_error_handler([this](zx_status_t status) {
      std::cerr << "FAILED: Subscriber channel disconnected unexpectedly, status " << status
                << ".\n";
      Quit(1);
    });

    resolver_ = component_context_->svc()->Connect<fuchsia::net::mdns::Resolver>();

    resolver_.set_error_handler([this](zx_status_t status) {
      std::cerr << "FAILED: Resolver channel disconnected unexpectedly, status " << status << ".\n";
      Quit(1);
    });

    fidl::InterfaceHandle<fuchsia::net::mdns::ServiceSubscriber> subscriber_handle;

    subscriber_binding_.Bind(subscriber_handle.NewRequest());
    subscriber_binding_.set_error_handler([this](zx_status_t status) {
      std::cerr << "FAILED: Subscriber channel disconnected unexpectedly, status " << status
                << ".\n";
      Quit(1);
    });

    subscriber_->SubscribeToService(kServiceName, std::move(subscriber_handle));

    resolver_->ResolveHostName(
        kRemoteHostName, kTimeout,
        [this](std::unique_ptr<fuchsia::net::Ipv4Address> v4_address,
               std::unique_ptr<fuchsia::net::Ipv6Address> v6_address) {
          if (!v4_address && !v6_address) {
            std::cerr << "FAILED: Host name resolution timed out.\n";
            Quit(1);
            return;
          }

          if (v4_address) {
            if (!fidl::Equals(*v4_address, kRemoteV4Address)) {
              std::cerr << "FAILED: Host name resolution produced bad V4 address " << *v4_address
                        << "\n";
              Quit(1);
              return;
            }
          } else if (v6_address) {
            // TODO(dalesat): Restore this check once we have predictable addresses in netemul.
            // if (!fidl::Equals(*v6_address, kRemoteV6Address)) {
            //   std::cerr << "FAILED: Host name resolution produced bad V6 address " << *v6_address
            //             << "\n";
            //   Quit(1);
            //   return;
            // }
          } else {
            std::cerr << "FAILED: Host name resolution produced no address\n";
            Quit(1);
            return;
          }

          std::cout << "Host name resolved correctly.\n";
          host_name_resolved_ = true;
          if (instance_discovered_) {
            Quit();
          }
        });
  }

 private:
  // fuchsia::net::mdns::ServiceSubscriber implementation.
  void OnInstanceDiscovered(fuchsia::net::mdns::ServiceInstance instance,
                            OnInstanceDiscoveredCallback callback) override {
    callback();
    if (VerifyInstance(instance)) {
      std::cout << "Discovered good instance.\n";
      instance_discovered_ = true;
      if (query_count_ == 0) {
        std::cerr << "FAILED: Never got OnQuery.\n";
        Quit(1);
      } else if (host_name_resolved_) {
        Quit();
      }
    } else {
      std::cerr << "FAILED: Discovered instance not compliant." << instance << "\n";
      Quit(1);
    }
  }

  void OnInstanceChanged(fuchsia::net::mdns::ServiceInstance instance,
                         OnInstanceChangedCallback callback) override {
    callback();
  }

  void OnInstanceLost(std::string service_name, std::string instance_name,
                      OnInstanceLostCallback callback) override {
    callback();
  }

  void OnQuery(fuchsia::net::mdns::ResourceType resource_type, OnQueryCallback callback) override {
    callback();
    ++query_count_;
  }

  void Quit(int exit_code = 0) {
    FX_DCHECK(quit_callback_);
    subscriber_.set_error_handler(nullptr);
    subscriber_.Unbind();
    subscriber_binding_.set_error_handler(nullptr);
    subscriber_binding_.Unbind();
    resolver_.set_error_handler(nullptr);
    resolver_.Unbind();
    quit_callback_(exit_code);
  }

  bool VerifyInstance(const fuchsia::net::mdns::ServiceInstance& instance) {
    return instance.service() == kServiceName && instance.instance() == kInstanceName &&
           VerifyRemoteEndpoints(instance) &&
           std::equal(kText.begin(), kText.end(), instance.text().begin(), instance.text().end()) &&
           instance.srv_priority() == kPriority && instance.srv_weight() == kWeight;
  }

  bool VerifyRemoteEndpoints(const fuchsia::net::mdns::ServiceInstance& instance) {
    bool valid_v4 = false;
    bool valid_v6 = false;
    if (instance.has_ipv4_endpoint()) {
      valid_v4 = instance.ipv4_endpoint().port == kPort &&
                 fidl::Equals(instance.ipv4_endpoint().address, kRemoteV4Address);
    }
    if (instance.has_ipv6_endpoint()) {
      // TODO(dalesat): Restore this check once we have predictable addresses in netemul.
      // fidl::Equals(endpoint.addr.ipv6(), kRemoteV6Address) &&
      valid_v6 = instance.ipv6_endpoint().port == kPort;
    }
    return valid_v4 || valid_v6;
  }

  sys::ComponentContext* component_context_;
  QuitCallback quit_callback_;
  fuchsia::net::mdns::SubscriberPtr subscriber_;
  fidl::Binding<fuchsia::net::mdns::ServiceSubscriber> subscriber_binding_;
  fuchsia::net::mdns::ResolverPtr resolver_;
  bool instance_discovered_ = false;
  bool host_name_resolved_ = false;
  uint32_t query_count_ = 0;
};

////////////////////////////////////////////////////////////////////////////////
// RemoteEnd
//
// An instance of this class runs as the 'remote' end of the test, responding
// to messages from the local end.
class RemoteEnd : public fuchsia::net::mdns::PublicationResponder {
 public:
  static std::unique_ptr<RemoteEnd> Create(sys::ComponentContext* component_context,
                                           QuitCallback quit_callback) {
    return std::make_unique<RemoteEnd>(component_context, std::move(quit_callback));
  }

  RemoteEnd(sys::ComponentContext* component_context, QuitCallback quit_callback)
      : component_context_(component_context),
        quit_callback_(std::move(quit_callback)),
        responder_binding_(this),
        responder_2_binding_(this) {
    publisher_ = component_context_->svc()->Connect<fuchsia::net::mdns::Publisher>();

    publisher_.set_error_handler([this](zx_status_t status) {
      std::cerr << "FAILED: Publisher channel disconnected unexpectedly, status " << status
                << ".\n";
      Quit(1);
    });

    fidl::InterfaceHandle<fuchsia::net::mdns::PublicationResponder> responder_handle;

    responder_binding_.Bind(responder_handle.NewRequest());
    responder_binding_.set_error_handler([this](zx_status_t status) {
      if (status != ZX_ERR_PEER_CLOSED) {
        std::cerr << "Responder channel disconnected unexpectedly, status " << status << ".\n";
        Quit(1);
        return;
      }

      responder_binding_.set_error_handler(nullptr);
      responder_binding_.Unbind();
    });

    publisher_->PublishServiceInstance(
        kServiceName, kInstanceName,
        fuchsia::net::mdns::Media::WIRED | fuchsia::net::mdns::Media::WIRED, true,
        std::move(responder_handle),
        [this](fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result) {
          if (result.is_response()) {
            std::cout << "Instance successfully published.\n";
          } else {
            std::cerr << "PublishServiceInstance failed, err " << result.err() << ".\n";
            Quit(1);
          }
        });

    // Ensure that the service guards against reannouncing when the instance probe hasn't yet
    // completed to avoid regressing b/144188577.
    responder_binding_.events().Reannounce();

    // Publish a second responder for the same service. This ensures that the service can handle
    // the responder being replaced when probing is still underway.
    responder_2_binding_.Bind(responder_handle.NewRequest());
    responder_2_binding_.set_error_handler([this](zx_status_t status) {
      std::cerr << "FAILED: Second responder channel disconnected unexpectedly, status " << status
                << ".\n";
      Quit(1);
    });

    publisher_->PublishServiceInstance(
        kServiceName, kInstanceName,
        fuchsia::net::mdns::Media::WIRED | fuchsia::net::mdns::Media::WIRED, true,
        std::move(responder_handle),
        [this](fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result) {
          if (result.is_response()) {
            std::cout << "Instance successfully republished.\n";
          } else {
            std::cerr << "PublishServiceInstance failed, err " << result.err() << ".\n";
            Quit(1);
          }
        });
  }

 private:
  // fuchsia::net::mdns::PublicationResponder implementation.
  void OnPublication(fuchsia::net::mdns::PublicationCause cause, fidl::StringPtr subtype,
                     std::vector<fuchsia::net::IpAddress> source_addresses,
                     OnPublicationCallback callback) override {
    auto publication = std::make_unique<fuchsia::net::mdns::Publication>();
    publication->port = kPort;
    publication->text = kText;
    publication->srv_priority = kPriority;
    publication->srv_weight = kWeight;

    for (const auto& source_address : source_addresses) {
      if (source_address.is_ipv4() && source_address.ipv4().addr != kLocalV4AddressA.addr &&
          source_address.ipv4().addr != kLocalV4AddressB.addr) {
        std::cerr << "Unrecognized source address\n";
        Quit(1);
      }
    }

    callback(std::move(publication));
  }

  void Quit(int exit_code = 0) {
    FX_DCHECK(quit_callback_);
    publisher_.set_error_handler(nullptr);
    publisher_.Unbind();
    responder_binding_.set_error_handler(nullptr);
    responder_binding_.Unbind();
    quit_callback_(exit_code);
  }

  sys::ComponentContext* component_context_;
  QuitCallback quit_callback_;
  fuchsia::net::mdns::PublisherPtr publisher_;
  fidl::Binding<fuchsia::net::mdns::PublicationResponder> responder_binding_;
  fidl::Binding<fuchsia::net::mdns::PublicationResponder> responder_2_binding_;
};

}  // namespace mdns::test

////////////////////////////////////////////////////////////////////////////////
// main
//
int main(int argc, const char** argv) {
  bool local = false;
  bool remote = false;

  for (int arg_index = 0; arg_index < argc; ++arg_index) {
    if (argv[arg_index] == kLocalArgument) {
      local = true;
    } else if (argv[arg_index] == kRemoteArgument) {
      remote = true;
    }
  }

  if (local == remote) {
    std::cout << "options: " << kLocalArgument << " | " << kRemoteArgument << "\n";
    return 1;
  }

  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);

  std::unique_ptr<sys::ComponentContext> component_context =
      sys::ComponentContext::CreateAndServeOutgoingDirectory();

  int result = 0;

  if (local) {
    auto local_end =
        mdns::test::LocalEnd::Create(component_context.get(), [&loop, &result](int exit_code) {
          result = exit_code;
          async::PostTask(loop.dispatcher(), [&loop]() { loop.Quit(); });
        });
    loop.Run();
  } else {
    FX_DCHECK(remote);
    auto remote_end =
        mdns::test::RemoteEnd::Create(component_context.get(), [&loop, &result](int exit_code) {
          result = exit_code;
          async::PostTask(loop.dispatcher(), [&loop]() { loop.Quit(); });
        });
    loop.Run();
  }

  return result;
}
