/*
 * SPDX-FileCopyrightText: 2026 Oak Ridge National Laboratory and Contributors
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ADIOS2_BINDINGS_PYTHON_VARIABLE_H_
#define ADIOS2_BINDINGS_PYTHON_VARIABLE_H_

#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>

#include "nbOperator.h"

#include "adios2/core/VariableBase.h"

namespace nb = nanobind;

namespace adios2
{
namespace py11
{

class IO;
class Engine;

class Variable
{
    friend class IO;
    friend class Engine;

public:
    Variable() = default;

    ~Variable() = default;

    explicit operator bool() const noexcept;

    void SetShape(const Dims &shape);

    void StoreStatsOnly(const bool mode);

    void SetBlockSelection(const size_t blockID);

    void SetSelection(const Box<Dims> &selection);

    void SetStepSelection(const Box<size_t> &stepSelection);

    size_t SelectionSize() const;

    void SetAccuracy(const adios2::Accuracy &a);
    adios2::Accuracy GetAccuracy() const;
    adios2::Accuracy GetAccuracyRequested() const;

    std::string Name() const;

    std::string Type() const;

    /**
     * Inspects size of the current element type, sizeof(T)
     * @return sizeof(T) for current system
     */
    size_t Sizeof() const;

    /**
     * Inspects shape id for current variable
     * @return from enum adios2::ShapeID
     */
    adios2::ShapeID ShapeID() const;

    /**
     * Inspects current shape
     * @return shape vector
     */
    Dims Shape(const size_t step = adios2::EngineCurrentStep) const;
#ifdef ADIOS2_HAVE_GPU_SUPPORT
    Dims Shape(const MemorySpace memSpace, const size_t step = adios2::EngineCurrentStep) const;

    void SetMemorySpace(const MemorySpace memSpace);
#endif

    /**
     * Inspects current start point
     * @return start vector
     */
    Dims Start() const;

    /**
     * Inspects current count from start
     * @return count vector
     */
    Dims Count() const;

    /**
     * For read mode, inspect the number of available steps
     * @return available steps
     */
    size_t Steps() const;

    /**
     * For read mode, inspect the start step for available steps
     * @return available start step
     */
    size_t StepsStart() const;

    size_t BlockID() const;

    size_t SingleValue() const;

    /**
     * EXPERIMENTAL: Adds operation and parameters to current Variable object
     * @param op operator to be added
     * @param parameters key/value settings particular to the Variable, not to
     * be confused by op own parameters
     * @return operation index handler in Operations()
     */
    size_t AddOperation(const Operator op, const Params &parameters = Params());

    /**
     * EXPERIMENTAL: Adds operation and parameters to current Variable object
     * @param op operator to be added
     * @param parameters key/value settings particular to the Variable, not to
     * be confused by op own parameters
     * @return operation index handler in Operations()
     */
    size_t AddOperation(const std::string &op, const Params &parameters = Params());

    /**
     * EXPERIMENTAL: inspects current operators added with AddOperator
     * @return vector of Variable<T>::OperatorInfo
     */
    std::vector<Operator> Operations() const;

    /**
     * Removes all current Operations associated with AddOperation.
     * Provides the posibility to apply or not operators on a step basis.
     */
    void RemoveOperations();

    /** Contains sub-block information for a particular Variable<T> */
    struct Info
    {
        Dims Start;
        Dims Count;
        nb::ndarray<nb::numpy> Min;
        nb::ndarray<nb::numpy> Max;
        nb::ndarray<nb::numpy> Value;
        bool IsValue;
    };

private:
    Variable(core::VariableBase *variable);

    core::VariableBase *m_VariableBase = nullptr;
};

} // end namespace py11
} // end namespace adios2

#endif /* ADIOS2_BINDINGS_PYTHON_PY11VARIABLE_H_ */
