// Copyright 2021 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/public/pw_bluetooth_sapphire/internal/host/common/windowed_inspect_numeric_property.h"

#include <pw_async/fake_dispatcher_fixture.h>

#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/inspect.h"

#ifndef NINSPECT

namespace bt {

namespace {

using namespace ::inspect::testing;

template <typename T>
class TestProperty {
 public:
  using ValueCallback = fit::function<void(const T& value)>;
  TestProperty() = default;
  TestProperty(T value, ValueCallback cb)
      : value_(value), value_cb_(std::move(cb)) {}

  void Add(const T& value) {
    value_ += value;
    if (value_cb_) {
      value_cb_(value_);
    }
  }

  void Subtract(const T& value) {
    value_ -= value;
    if (value_cb_) {
      value_cb_(value_);
    }
  }

 private:
  T value_;
  fit::function<void(const T& value)> value_cb_;
};

using WindowedProperty = WindowedInspectNumericProperty<TestProperty<int>, int>;
using WindowedInspectNumericPropertyTest =
    pw::async::test::FakeDispatcherFixture;

TEST_F(WindowedInspectNumericPropertyTest, AddTwoValues) {
  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  WindowedProperty windowed_prop(dispatcher(), kExpiryDuration);
  int value = 0;
  auto value_cb = [&](auto val) { value = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb));

  windowed_prop.Add(1);
  EXPECT_EQ(value, 1);
  RunFor(std::chrono::minutes(1));
  EXPECT_EQ(value, 1);

  windowed_prop.Add(2);
  EXPECT_EQ(value, 3);
  RunFor(std::chrono::minutes(1));
  EXPECT_EQ(value, 3);

  // Let first value expire.
  RunFor(std::chrono::minutes(1));
  EXPECT_EQ(value, 2);
  // Let second value expire.
  RunFor(std::chrono::minutes(1));
  EXPECT_EQ(value, 0);

  // Ensure timer doesn't fire again.
  RunFor(kExpiryDuration);
  EXPECT_EQ(value, 0);
}

TEST_F(WindowedInspectNumericPropertyTest, AddTwoValuesAtSameTime) {
  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  WindowedProperty windowed_prop(dispatcher(), kExpiryDuration);
  int value = 0;
  auto value_cb = [&](auto val) { value = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb));

  windowed_prop.Add(1);
  windowed_prop.Add(2);
  EXPECT_EQ(value, 3);
  RunFor(std::chrono::minutes(1));
  EXPECT_EQ(value, 3);
  RunFor(std::chrono::minutes(2));
  EXPECT_EQ(value, 0);

  // Ensure timer doesn't fire again.
  RunFor(kExpiryDuration);
  EXPECT_EQ(value, 0);
}

TEST_F(WindowedInspectNumericPropertyTest, AddValueThenExpireThenAddValue) {
  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  WindowedProperty windowed_prop(dispatcher(), kExpiryDuration);
  int value = 0;
  auto value_cb = [&](auto val) { value = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb));

  windowed_prop.Add(1);
  EXPECT_EQ(value, 1);
  RunFor(kExpiryDuration);
  EXPECT_EQ(value, 0);

  windowed_prop.Add(2);
  EXPECT_EQ(value, 2);
  RunFor(kExpiryDuration);
  EXPECT_EQ(value, 0);

  // Ensure timer doesn't fire again.
  RunFor(kExpiryDuration);
  EXPECT_EQ(value, 0);
}

TEST_F(WindowedInspectNumericPropertyTest,
       AddTwoValuesWithinResolutionIntervalExpiresBothSimultaneously) {
  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  constexpr pw::chrono::SystemClock::duration kResolution =
      std::chrono::seconds(3);
  WindowedProperty windowed_prop(dispatcher(), kExpiryDuration, kResolution);
  int value = 0;
  auto value_cb = [&](auto val) { value = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb));

  // First two values are within kResolution of each other in time.
  windowed_prop.Add(1);
  constexpr pw::chrono::SystemClock::duration kTinyDuration =
      std::chrono::milliseconds(1);
  RunFor(kTinyDuration);
  windowed_prop.Add(1);
  EXPECT_EQ(value, 2);

  // Third value is spaced kResolution apart from the first value.
  RunFor(kResolution - kTinyDuration);
  windowed_prop.Add(1);
  EXPECT_EQ(value, 3);

  // Let first value expire.
  RunFor(kExpiryDuration - kResolution);

  // First and second values should have expired because they were merged.
  EXPECT_EQ(value, 1);

  // Let third value expire.
  RunFor(kResolution);
  EXPECT_EQ(value, 0);
}

TEST_F(WindowedInspectNumericPropertyTest, SetPropertyClearsValueAndTimer) {
  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  WindowedProperty windowed_prop(dispatcher(), kExpiryDuration);
  int value_0 = 0;
  auto value_cb_0 = [&](auto val) { value_0 = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb_0));

  windowed_prop.Add(1);
  EXPECT_EQ(value_0, 1);
  int value_1 = 0;
  auto value_cb_1 = [&](auto val) { value_1 = val; };
  windowed_prop.SetProperty(TestProperty<int>(0, value_cb_1));
  // Ensure timer doesn't fire.
  RunFor(kExpiryDuration);
  EXPECT_EQ(value_0, 1);
  EXPECT_EQ(value_1, 0);

  // Ensure values can be added to new property.
  windowed_prop.Add(3);
  EXPECT_EQ(value_0, 1);
  EXPECT_EQ(value_1, 3);
  RunFor(kExpiryDuration);
  EXPECT_EQ(value_0, 1);
  EXPECT_EQ(value_1, 0);
}

TEST_F(WindowedInspectNumericPropertyTest, AttachInspectRealIntProperty) {
  ::inspect::Inspector inspector;
  auto& root = inspector.GetRoot();

  constexpr pw::chrono::SystemClock::duration kExpiryDuration =
      std::chrono::minutes(3);
  WindowedInspectIntProperty windowed_property(dispatcher(), kExpiryDuration);
  windowed_property.AttachInspect(root, "windowed");

  auto hierarchy = ::inspect::ReadFromVmo(inspector.DuplicateVmo());
  ASSERT_TRUE(hierarchy.is_ok());
  EXPECT_THAT(
      hierarchy.take_value(),
      AllOf(NodeMatches(PropertyList(ElementsAre(IntIs("windowed", 0))))));

  windowed_property.Add(7);

  hierarchy = ::inspect::ReadFromVmo(inspector.DuplicateVmo());
  ASSERT_TRUE(hierarchy.is_ok());
  EXPECT_THAT(
      hierarchy.take_value(),
      AllOf(NodeMatches(PropertyList(ElementsAre(IntIs("windowed", 7))))));
}

}  // namespace

}  // namespace bt

#endif  // NINSPECT
