// 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 "src/connectivity/bluetooth/core/bt-host/sdp/service_discoverer.h"

#include <lib/async/default.h>

#include <gtest/gtest.h>

#include "src/connectivity/bluetooth/core/bt-host/common/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_channel_test.h"

namespace bt {
namespace sdp {
namespace {

using TestingBase = ::gtest::TestLoopFixture;

constexpr PeerId kDeviceOne(1), kDeviceTwo(2), kDeviceThree(3);

class FakeClient : public Client {
 public:
  // |destroyed_cb| will be called when this client is destroyed, with true if
  // there are outstanding expected requests.
  FakeClient(fit::closure destroyed_cb) : destroyed_cb_(std::move(destroyed_cb)) {}

  virtual ~FakeClient() override { destroyed_cb_(); }

  virtual void ServiceSearchAttributes(std::unordered_set<UUID> search_pattern,
                                       const std::unordered_set<AttributeId> &req_attributes,
                                       SearchResultCallback result_cb,
                                       async_dispatcher_t *cb_dispatcher) override {
    if (!service_search_attributes_cb_) {
      FAIL() << "ServiceSearchAttributes with no callback set";
    }

    service_search_attributes_cb_(std::move(search_pattern), std::move(req_attributes),
                                  std::move(result_cb), cb_dispatcher);
  }

  using ServiceSearchAttributesCalllback =
      fit::function<void(std::unordered_set<UUID>, std::unordered_set<AttributeId>,
                         SearchResultCallback, async_dispatcher_t *)>;
  void SetServiceSearchAttributesCallback(ServiceSearchAttributesCalllback callback) {
    service_search_attributes_cb_ = std::move(callback);
  }

 private:
  ServiceSearchAttributesCalllback service_search_attributes_cb_;
  fit::closure destroyed_cb_;
};

class SDP_ServiceDiscovererTest : public TestingBase {
 public:
  SDP_ServiceDiscovererTest() = default;
  ~SDP_ServiceDiscovererTest() = default;

 protected:
  void SetUp() override {
    clients_created_ = 0;
    clients_destroyed_ = 0;
  }

  void TearDown() override {}

  // Connect an SDP client to a fake channel, which is available in channel_
  std::unique_ptr<FakeClient> GetFakeClient() {
    SCOPED_TRACE("Connect Client");
    clients_created_++;
    return std::make_unique<FakeClient>([this]() { clients_destroyed_++; });
  }

  size_t clients_created() const { return clients_created_; };
  size_t clients_destroyed() const { return clients_destroyed_; };

 private:
  size_t clients_created_, clients_destroyed_;
};

// When there are no searches registered, it just disconnects the client.
TEST_F(SDP_ServiceDiscovererTest, NoSearches) {
  ServiceDiscoverer discoverer;
  EXPECT_EQ(0u, discoverer.search_count());

  discoverer.StartServiceDiscovery(kDeviceOne, GetFakeClient());

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(1u, clients_destroyed());
}

// Happy path test with one registered service and no results.
TEST_F(SDP_ServiceDiscovererTest, NoResults) {
  ServiceDiscoverer discoverer;

  size_t cb_count = 0;

  auto result_cb = [&cb_count](auto, const auto &) { cb_count++; };

  ServiceDiscoverer::SearchId id = discoverer.AddSearch(
      profile::kSerialPort, {kServiceId, kProtocolDescriptorList, kBluetoothProfileDescriptorList},
      std::move(result_cb));
  ASSERT_NE(ServiceDiscoverer::kInvalidSearchId, id);
  EXPECT_EQ(1u, discoverer.search_count());

  auto client = GetFakeClient();

  std::vector<std::unordered_set<UUID>> searches;

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(std::move(pattern));
        async::PostTask(cb_dispatcher,
                        [cb = std::move(callback)]() { cb(Status(HostError::kNotFound), {}); });
      });

  discoverer.StartServiceDiscovery(kDeviceOne, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(1u, searches.size());
  ASSERT_EQ(0u, cb_count);
  ASSERT_EQ(1u, clients_destroyed());
}

// Happy path test with two registered searches.
// No results, then two results.
// Unregister one search.
// Then one result are searched for and two returned.
TEST_F(SDP_ServiceDiscovererTest, SomeResults) {
  ServiceDiscoverer discoverer;

  std::vector<std::pair<PeerId, std::map<AttributeId, DataElement>>> results;

  ServiceDiscoverer::ResultCallback result_cb = [&results](PeerId id, const auto &attributes) {
    std::map<AttributeId, DataElement> attributes_clone;
    for (const auto &it : attributes) {
      auto [inserted_it, added] = attributes_clone.try_emplace(it.first, it.second.Clone());
      ASSERT_TRUE(added);
    }
    results.emplace_back(id, std::move(attributes_clone));
  };

  ServiceDiscoverer::SearchId one = discoverer.AddSearch(
      profile::kSerialPort, {kServiceId, kProtocolDescriptorList, kBluetoothProfileDescriptorList},
      result_cb.share());
  ASSERT_NE(ServiceDiscoverer::kInvalidSearchId, one);
  EXPECT_EQ(1u, discoverer.search_count());
  ServiceDiscoverer::SearchId two = discoverer.AddSearch(
      profile::kAudioSink, {kProtocolDescriptorList, kBluetoothProfileDescriptorList},
      result_cb.share());
  ASSERT_NE(ServiceDiscoverer::kInvalidSearchId, two);
  EXPECT_EQ(2u, discoverer.search_count());

  auto client = GetFakeClient();

  std::vector<std::unordered_set<UUID>> searches;

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(std::move(pattern));
        async::PostTask(cb_dispatcher,
                        [cb = std::move(callback)]() { cb(Status(HostError::kNotFound), {}); });
      });

  discoverer.StartServiceDiscovery(kDeviceOne, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(2u, searches.size());
  ASSERT_EQ(0u, results.size());
  ASSERT_EQ(1u, clients_destroyed());

  client = GetFakeClient();

  searches.clear();

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(pattern);
        if (pattern.count(profile::kSerialPort)) {
          async::PostTask(cb_dispatcher, [cb = std::move(callback)]() {
            ServiceSearchAttributeResponse rsp;
            rsp.SetAttribute(0, kServiceId, DataElement(UUID(uint16_t(1))));
            // This would normally be a element list. uint32_t for Testing.
            rsp.SetAttribute(0, kBluetoothProfileDescriptorList, DataElement(uint32_t(1)));

            if (!cb(Status(), rsp.attributes(0))) {
              return;
            }
            cb(Status(HostError::kNotFound), {});
          });
        } else if (pattern.count(profile::kAudioSink)) {
          async::PostTask(cb_dispatcher, [cb = std::move(callback)]() {
            ServiceSearchAttributeResponse rsp;
            // This would normally be a element list. uint32_t for Testing.
            rsp.SetAttribute(0, kBluetoothProfileDescriptorList, DataElement(uint32_t(1)));

            if (!cb(Status(), rsp.attributes(0))) {
              return;
            }
            cb(Status(HostError::kNotFound), {});
          });
        } else {
          std::cerr << "Searched for " << pattern.size() << std::endl;
          for (auto it : pattern) {
            std::cerr << it.ToString() << std::endl;
          }
          FAIL() << "Unexpected search called";
        }
      });

  discoverer.StartServiceDiscovery(kDeviceTwo, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(2u, searches.size());
  ASSERT_EQ(2u, results.size());
  ASSERT_EQ(2u, clients_destroyed());

  results.clear();
  searches.clear();

  ASSERT_TRUE(discoverer.RemoveSearch(one));
  ASSERT_FALSE(discoverer.RemoveSearch(one));
  EXPECT_EQ(1u, discoverer.search_count());

  client = GetFakeClient();

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(pattern);
        if (pattern.count(profile::kAudioSink)) {
          async::PostTask(cb_dispatcher, [cb = std::move(callback)]() {
            ServiceSearchAttributeResponse rsp;
            // This would normally be a element list. uint32_t for Testing.
            rsp.SetAttribute(0, kBluetoothProfileDescriptorList, DataElement(uint32_t(1)));
            rsp.SetAttribute(1, kProtocolDescriptorList, DataElement(uint32_t(2)));

            if (!cb(Status(), rsp.attributes(0))) {
              return;
            }
            if (!cb(Status(), rsp.attributes(1))) {
              return;
            }
            cb(Status(HostError::kNotFound), {});
          });
        } else {
          std::cerr << "Searched for " << pattern.size() << std::endl;
          for (auto it : pattern) {
            std::cerr << it.ToString() << std::endl;
          }
          FAIL() << "Unexpected search called";
        }
      });

  discoverer.StartServiceDiscovery(kDeviceThree, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(1u, searches.size());
  ASSERT_EQ(2u, results.size());
  ASSERT_EQ(3u, clients_destroyed());
}

// Disconnected on the other end before the discovery completes
TEST_F(SDP_ServiceDiscovererTest, Disconnected) {
  ServiceDiscoverer discoverer;

  size_t cb_count = 0;

  auto result_cb = [&cb_count](auto, const auto &) { cb_count++; };

  ServiceDiscoverer::SearchId id = discoverer.AddSearch(
      profile::kSerialPort, {kServiceId, kProtocolDescriptorList, kBluetoothProfileDescriptorList},
      std::move(result_cb));
  ASSERT_NE(ServiceDiscoverer::kInvalidSearchId, id);
  EXPECT_EQ(1u, discoverer.search_count());

  auto client = GetFakeClient();

  std::vector<std::unordered_set<UUID>> searches;

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(pattern);
        if (pattern.count(profile::kSerialPort)) {
          async::PostTask(cb_dispatcher, [cb = std::move(callback)]() {
            cb(Status(HostError::kLinkDisconnected), {});
          });
        } else {
          std::cerr << "Searched for " << pattern.size() << std::endl;
          for (auto it : pattern) {
            std::cerr << it.ToString() << std::endl;
          }
          FAIL() << "Unexpected search called";
        }
      });

  discoverer.StartServiceDiscovery(kDeviceOne, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(1u, searches.size());
  ASSERT_EQ(0u, cb_count);
  ASSERT_EQ(1u, clients_destroyed());
}

// Unregistered Search when partway through the discovery
TEST_F(SDP_ServiceDiscovererTest, UnregisterInProgress) {
  ServiceDiscoverer discoverer;

  std::optional<std::pair<PeerId, std::map<AttributeId, DataElement>>> result;

  ServiceDiscoverer::SearchId id = ServiceDiscoverer::kInvalidSearchId;

  ServiceDiscoverer::ResultCallback one_result_cb = [&discoverer, &result, &id](
                                                        auto peer_id, const auto &attributes) {
    // We should only be called once
    ASSERT_TRUE(!result.has_value());
    std::map<AttributeId, DataElement> attributes_clone;
    for (const auto &it : attributes) {
      auto [inserted_it, added] = attributes_clone.try_emplace(it.first, it.second.Clone());
      ASSERT_TRUE(added);
    }
    result.emplace(peer_id, std::move(attributes_clone));
    discoverer.RemoveSearch(id);
  };

  id = discoverer.AddSearch(profile::kAudioSink,
                            {kProtocolDescriptorList, kBluetoothProfileDescriptorList},
                            one_result_cb.share());
  ASSERT_NE(ServiceDiscoverer::kInvalidSearchId, id);
  EXPECT_EQ(1u, discoverer.search_count());

  auto client = GetFakeClient();

  std::vector<std::unordered_set<UUID>> searches;

  client->SetServiceSearchAttributesCallback(
      [&searches](auto pattern, auto attributes, auto callback, auto *cb_dispatcher) {
        searches.emplace_back(pattern);
        if (pattern.count(profile::kAudioSink)) {
          async::PostTask(cb_dispatcher, [cb = std::move(callback)]() {
            ServiceSearchAttributeResponse rsp;
            // This would normally be a element list. uint32_t for Testing.
            rsp.SetAttribute(0, kBluetoothProfileDescriptorList, DataElement(uint32_t(1)));
            rsp.SetAttribute(1, kProtocolDescriptorList, DataElement(uint32_t(2)));

            if (!cb(Status(), rsp.attributes(0))) {
              return;
            }
            if (!cb(Status(), rsp.attributes(1))) {
              return;
            }
            cb(Status(HostError::kNotFound), {});
          });
        } else {
          std::cerr << "Searched for " << pattern.size() << std::endl;
          for (auto it : pattern) {
            std::cerr << it.ToString() << std::endl;
          }
          FAIL() << "Unexpected search called";
        }
      });

  discoverer.StartServiceDiscovery(kDeviceOne, std::move(client));

  RETURN_IF_FATAL(RunLoopUntilIdle());

  EXPECT_EQ(1u, searches.size());

  ASSERT_TRUE(result.has_value());
  ASSERT_EQ(kDeviceOne, result->first);
  auto value = result->second[kBluetoothProfileDescriptorList].Get<uint32_t>();
  ASSERT_TRUE(value);
  ASSERT_EQ(1u, *value);

  ASSERT_EQ(1u, clients_destroyed());
  EXPECT_EQ(0u, discoverer.search_count());
}

}  // namespace
}  // namespace sdp
}  // namespace bt
