/*
 * Copyright 2020 The Android Open Source Project
 *
 * 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
 *
 *      http://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 "service/a2dp_source.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "service/hal/fake_bluetooth_av_interface.h"
#include "types/raw_address.h"

using ::testing::_;
using ::testing::Return;

namespace bluetooth {
namespace {

class MockA2dpSourceHandler
    : public hal::FakeBluetoothAvInterface::TestA2dpSourceHandler {
 public:
  MockA2dpSourceHandler() = default;
  ~MockA2dpSourceHandler() override = default;

  MOCK_METHOD1(Connect, bt_status_t(RawAddress));
  MOCK_METHOD1(Disconnect, bt_status_t(RawAddress));

 private:
  DISALLOW_COPY_AND_ASSIGN(MockA2dpSourceHandler);
};

class TestDelegate : public A2dpSource::Delegate {
 public:
  TestDelegate() = default;
  ~TestDelegate() override = default;

  struct RequestData {
    std::string device_address;
    int state = -1;
    int count = 0;
  };

  // A2dpSource::Delegate implementation:
  void OnConnectionState(const std::string& device_address,
                         int state) override {
    ++connection_state_.count;
    connection_state_.device_address = device_address;
    connection_state_.state = state;
  }
  void OnAudioState(const std::string& device_address, int state) override {
    ++audio_state_.count;
    audio_state_.device_address = device_address;
    audio_state_.state = state;
  }
  void OnAudioConfig(
      const std::string& device_address, A2dpCodecConfig codec_config,
      const std::vector<A2dpCodecConfig>& codecs_local_capabilities,
      const std::vector<A2dpCodecConfig>& codecs_selectable_capabilities)
      override {
    ++audio_config_.count;
    audio_config_.device_address = device_address;
  }

  const RequestData& connection_state() const { return connection_state_; }
  const RequestData& audio_state() const { return audio_state_; }
  const RequestData& audio_config() const { return audio_config_; }

 private:
  RequestData connection_state_;
  RequestData audio_state_;
  RequestData audio_config_;
};

class A2dpSourceTest : public ::testing::Test {
 public:
  A2dpSourceTest() = default;
  ~A2dpSourceTest() override = default;

  void SetUp() override {
    mock_handler_.reset(new MockA2dpSourceHandler());
    fake_hal_av_iface_ = new hal::FakeBluetoothAvInterface(mock_handler_);
    hal::BluetoothAvInterface::InitializeForTesting(fake_hal_av_iface_);
    factory_.reset(new A2dpSourceFactory());
  }

  void TearDown() override {
    factory_.reset();
    hal::BluetoothAvInterface::CleanUp();
  }

 protected:
  hal::FakeBluetoothAvInterface* fake_hal_av_iface_;
  std::shared_ptr<MockA2dpSourceHandler> mock_handler_;
  std::unique_ptr<A2dpSourceFactory> factory_;

 private:
  DISALLOW_COPY_AND_ASSIGN(A2dpSourceTest);
};

class A2dpSourcePostRegisterTest : public A2dpSourceTest {
 public:
  A2dpSourcePostRegisterTest() = default;
  ~A2dpSourcePostRegisterTest() override = default;

  void SetUp() override {
    A2dpSourceTest::SetUp();
    Uuid uuid = Uuid::GetRandom();
    auto callback = [&](BLEStatus status, const Uuid& in_uuid,
                        std::unique_ptr<BluetoothInstance> in_client) {
      CHECK(in_uuid == uuid);
      CHECK(in_client.get());
      CHECK(status == BLE_STATUS_SUCCESS);

      a2dp_source_ = std::unique_ptr<A2dpSource>(
          static_cast<A2dpSource*>(in_client.release()));
    };

    factory_->RegisterInstance(uuid, callback);
  }

  void TearDown() override {
    a2dp_source_ = nullptr;
    A2dpSourceTest::TearDown();
  }

 protected:
  void Connect(const std::string& addr) {
    RawAddress hal_addr;
    ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));

    EXPECT_CALL(*mock_handler_, Connect(hal_addr))
        .WillOnce(Return(BT_STATUS_SUCCESS));

    EXPECT_TRUE(a2dp_source_->Connect(addr));
  }

  void Disconnect(const std::string& addr) {
    RawAddress hal_addr;
    ASSERT_TRUE(RawAddress::FromString(addr, hal_addr));

    EXPECT_CALL(*mock_handler_, Disconnect(hal_addr))
        .WillOnce(Return(BT_STATUS_SUCCESS));

    EXPECT_TRUE(a2dp_source_->Disconnect(addr));
  }

  std::unique_ptr<A2dpSource> a2dp_source_;

 private:
  DISALLOW_COPY_AND_ASSIGN(A2dpSourcePostRegisterTest);
};

TEST_F(A2dpSourceTest, RegisterA2dpSource) {
  // These will be asynchronously populate with a result when the callback
  // executes.
  BLEStatus status = BLE_STATUS_SUCCESS;
  Uuid cb_uuid;
  std::unique_ptr<A2dpSource> a2dp_source;
  int callback_count = 0;

  auto callback = [&](BLEStatus in_status, const Uuid& uuid,
                      std::unique_ptr<BluetoothInstance> in_a2dp_source) {
    status = in_status;
    cb_uuid = uuid;
    a2dp_source = std::unique_ptr<A2dpSource>(
        static_cast<A2dpSource*>(in_a2dp_source.release()));
    callback_count++;
  };

  Uuid uuid0 = Uuid::GetRandom();

  // This should always succeed.
  EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
  EXPECT_EQ(1, callback_count);

  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());

  ASSERT_TRUE(a2dp_source.get() !=
              nullptr);  // Assert to terminate in case of error
  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
  EXPECT_EQ(bluetooth::A2dpSource::kSingletonInstanceId,
            a2dp_source->GetInstanceId());
  EXPECT_EQ(uuid0, a2dp_source->GetAppIdentifier());
  EXPECT_EQ(uuid0, cb_uuid);

  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
}

TEST_F(A2dpSourcePostRegisterTest, Connect) {
  static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
  Connect(kTestAddr);
  Disconnect(kTestAddr);
}

TEST_F(A2dpSourcePostRegisterTest, CallbackTest) {
  static const char kTestAddr[] = "AA:BB:CC:DD:EE:FF";
  RawAddress hal_addr;
  ASSERT_TRUE(RawAddress::FromString(kTestAddr, hal_addr));

  TestDelegate delegate;
  a2dp_source_->SetDelegate(&delegate);
  Connect(kTestAddr);

  // OnConnectionState
  const int kConnectionState = 2;
  EXPECT_EQ(0, delegate.connection_state().count);
  fake_hal_av_iface_->NotifyConnectionState(
      hal_addr, static_cast<btav_connection_state_t>(kConnectionState));
  EXPECT_EQ(1, delegate.connection_state().count);
  EXPECT_EQ(kTestAddr, delegate.connection_state().device_address);
  EXPECT_EQ(kConnectionState, delegate.connection_state().state);

  // OnAudioState
  const int kAudioState = 1;
  EXPECT_EQ(0, delegate.audio_state().count);
  fake_hal_av_iface_->NotifyAudioState(
      hal_addr, static_cast<btav_audio_state_t>(kAudioState));
  EXPECT_EQ(1, delegate.audio_state().count);
  EXPECT_EQ(kTestAddr, delegate.audio_state().device_address);
  EXPECT_EQ(kAudioState, delegate.audio_state().state);

  // OnAudioConfig
  const btav_a2dp_codec_config_t codec_config{};
  const std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities(0);
  const std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities(0);
  EXPECT_EQ(0, delegate.audio_config().count);
  fake_hal_av_iface_->NotifyAudioConfig(hal_addr, codec_config,
                                        codecs_local_capabilities,
                                        codecs_selectable_capabilities);
  EXPECT_EQ(1, delegate.audio_config().count);
  EXPECT_EQ(kTestAddr, delegate.audio_config().device_address);

  fake_hal_av_iface_->QueryMandatoryCodecPreferred(hal_addr);

  Disconnect(kTestAddr);
}

}  // namespace
}  // namespace bluetooth
