#ifndef _RIVE_LAZY_VECTOR_HPP_
#define _RIVE_LAZY_VECTOR_HPP_

#include <algorithm>
#include <cstddef>
#include <utility>
#include <vector>

namespace rive
{

// 8 B owning pointer to a heap-allocated std::vector<T>, allocated on first
// mutation. Saves 16 B per object compared to an inline std::vector<T> (24 B
// header) for fields that are empty most of the time.
//
// Use when you have a per-object list that's empty for the majority of
// instances (typical fits: dependents/observers/optional adornments). Do NOT
// use when the vector is usually populated — the extra heap allocation makes
// it strictly worse than a regular vector for that case.
//
// All read operations are safe on an empty (never-allocated) wrapper. The
// hot-path null check is a single load + branch; reads return iterators into
// a shared static empty vector when the wrapper has no backing storage.
template <typename T> class LazyVector
{
public:
  using value_type = T;
  using const_iterator = typename std::vector<T>::const_iterator;

  LazyVector() = default;
  ~LazyVector() { delete m_v; }

  // Deep copy. Preserves the "copying the owner clones its list" semantic
  // that a plain std::vector member would have provided. An empty source
  // (m_v == nullptr) copies as an empty wrapper — no allocation. This
  // keeps Component / Drawable / etc. copyable (Core::clone path).
  LazyVector(const LazyVector& other)
      : m_v(other.m_v != nullptr ? new std::vector<T>(*other.m_v) : nullptr)
  {}
  LazyVector& operator=(const LazyVector& other)
  {
    if (this != &other)
    {
      delete m_v;
      m_v = other.m_v != nullptr ? new std::vector<T>(*other.m_v) : nullptr;
    }
    return *this;
  }

  LazyVector(LazyVector&& other) noexcept : m_v(other.m_v)
  {
    other.m_v = nullptr;
  }
  LazyVector& operator=(LazyVector&& other) noexcept
  {
    if (this != &other)
    {
      delete m_v;
      m_v = other.m_v;
      other.m_v = nullptr;
    }
    return *this;
  }

  bool empty() const { return m_v == nullptr || m_v->empty(); }
  std::size_t size() const { return m_v == nullptr ? 0 : m_v->size(); }

  // Append unconditionally. Allows duplicates (use pushUnique to dedup).
  void push_back(T value)
  {
    if (m_v == nullptr)
    {
      m_v = new std::vector<T>();
    }
    m_v->push_back(std::move(value));
  }

  // Append only if `value` is not already present. Centralizes the
  // find-then-push idiom used by callers that maintain set semantics.
  void pushUnique(T value)
  {
    if (m_v != nullptr &&
        std::find(m_v->begin(), m_v->end(), value) != m_v->end())
    {
      return;
    }
    push_back(std::move(value));
  }

  // Erase every element equal to `value`. No-op when wrapper is empty.
  // Uses the erase-remove idiom — safe but removes ALL duplicates if any.
  void eraseAll(const T& value)
  {
    if (m_v == nullptr)
    {
      return;
    }
    m_v->erase(std::remove(m_v->begin(), m_v->end(), value), m_v->end());
  }

  // Replace every element equal to `value` in place, so iterators held
  // across the call stay valid.
  void replaceAll(const T& value, const T& with)
  {
    if (m_v != nullptr)
    {
      std::replace(m_v->begin(), m_v->end(), value, with);
    }
  }

  // Erase every element matching `predicate`. No-op when the wrapper is
  // empty. The erase-remove counterpart to eraseAll for callers that select
  // by a property of the element rather than by equality.
  template <typename Predicate> void eraseIf(Predicate predicate)
  {
    if (m_v == nullptr)
    {
      return;
    }
    m_v->erase(std::remove_if(m_v->begin(), m_v->end(), predicate), m_v->end());
  }

  void clear()
  {
    if (m_v != nullptr)
    {
      m_v->clear();
    }
  }

  // Const iteration always works, even on a never-allocated wrapper —
  // returns iterators into a shared static empty vector when m_v is null.
  // Inlined null check (no view() indirection) so the compiler can keep
  // m_v in a register across both begin/end loads in a range-for.
  const_iterator begin() const
  {
    return m_v ? m_v->begin() : emptyView().begin();
  }
  const_iterator end() const { return m_v ? m_v->end() : emptyView().end(); }

  // Returns a stable const reference suitable as the return value of
  // accessor methods. Always valid — falls back to a shared empty when
  // the wrapper has no backing storage.
  const std::vector<T>& view() const { return m_v ? *m_v : emptyView(); }

private:
  std::vector<T>* m_v = nullptr;

  static const std::vector<T>& emptyView()
  {
    static const std::vector<T> EMPTY;
    return EMPTY;
  }
};

} // namespace rive
#endif
