// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later

// vector_base.hpp
//
// Definition of the vector base class
//
// This file defines the base class for the vector classes of the MKL
// algebra library. The base class provides functionality common to
// vector classes that may use different storage strategies.
//
// Main features:
// - Common vector interface
// - Storage-independent operations
// - Iterators and accessors

#ifndef SANGI_VECTOR_BASE_HPP
#define SANGI_VECTOR_BASE_HPP

#include "vector_storage.hpp"
#include "../common.hpp"
#include <math/concepts/algebraic_concepts.hpp>
#include <math/core/traits.hpp>

#include <cstddef>
#include <initializer_list>
#include <type_traits>

namespace sangi {
namespace detail {

//-----------------------------------------------------------------------------
// Vector base class
//-----------------------------------------------------------------------------

template<typename T, typename StoragePolicy>
    requires concepts::AdditiveGroup<T>  // Require the additive group concept
class VectorBase {
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using reference = T&;
    using const_reference = const T&;
    using pointer = T*;
    using const_pointer = const T*;
    using iterator = typename StoragePolicy::iterator;
    using const_iterator = typename StoragePolicy::const_iterator;

    // Default constructor (depends on the storage policy)
    VectorBase() = default;

    // Size-specifying constructor
    explicit VectorBase(size_type size) : storage_(size) {}

    // Constructor specifying size and initial value
    VectorBase(size_type size, const T& value) : storage_(size, value) {}

    // Iterator-range constructor
    template<typename InputIt>
    VectorBase(InputIt first, InputIt last) : storage_(first, last) {}

    // Initializer-list constructor
    VectorBase(std::initializer_list<T> init) : storage_(init) {}

    // Copy/move constructors and copy/move assignment operators (default)
    VectorBase(const VectorBase&) = default;
    VectorBase(VectorBase&&) noexcept = default;
    VectorBase& operator=(const VectorBase&) = default;
    VectorBase& operator=(VectorBase&&) noexcept = default;

    // Destructor
    ~VectorBase() = default;

    // Element access

    // Subscript access (non-const)
    reference operator[](size_type pos) {
        return storage_[pos];
    }

    // Subscript access (const)
    const_reference operator[](size_type pos) const {
        return storage_[pos];
    }

    // Range-checked subscript access (non-const)
    reference at(size_type pos) {
        return storage_.at(pos);
    }

    // Range-checked subscript access (const)
    const_reference at(size_type pos) const {
        return storage_.at(pos);
    }

    // Front element access (non-const)
    reference front() {
        if (empty()) {
            throw IndexError("VectorBase::front: empty container");
        }
        return storage_.front();
    }

    // Front element access (const)
    const_reference front() const {
        if (empty()) {
            throw IndexError("VectorBase::front: empty container");
        }
        return storage_.front();
    }

    // Back element access (non-const)
    reference back() {
        if (empty()) {
            throw IndexError("VectorBase::back: empty container");
        }
        return storage_.back();
    }

    // Back element access (const)
    const_reference back() const {
        if (empty()) {
            throw IndexError("VectorBase::back: empty container");
        }
        return storage_.back();
    }

    // Data pointer access (non-const)
    T* data() noexcept {
        return storage_.data();
    }

    // Data pointer access (const)
    const T* data() const noexcept {
        return storage_.data();
    }

    // Iterators

    // Begin iterator (non-const)
    iterator begin() noexcept {
        return storage_.begin();
    }

    // Begin iterator (const)
    const_iterator begin() const noexcept {
        return storage_.begin();
    }

    // Begin iterator (always const)
    const_iterator cbegin() const noexcept {
        return storage_.cbegin();
    }

    // End iterator (non-const)
    iterator end() noexcept {
        return storage_.end();
    }

    // End iterator (const)
    const_iterator end() const noexcept {
        return storage_.end();
    }

    // End iterator (always const)
    const_iterator cend() const noexcept {
        return storage_.cend();
    }

    // Capacity

    // Check whether the container is empty
    bool empty() const noexcept {
        return storage_.empty();
    }

    // Get the size
    size_type size() const noexcept {
        return storage_.size();
    }

    // Set every element to a scalar value
    void fill(const T& value) {
        std::fill(begin(), end(), value);
    }

    // Zero-clear
    void zero() {
        fill(numeric_traits<T>::zero());
    }

    // Get the underlying storage (implementation detail)
    StoragePolicy& storage() noexcept {
        return storage_;
    }

    const StoragePolicy& storage() const noexcept {
        return storage_;
    }

protected:
    StoragePolicy storage_;
};

} // namespace detail
} // namespace sangi

#endif // SANGI_VECTOR_BASE_HPP
