#pragma once

#include <memory>
#include <string>

// Forward declaration so tinyexpr.h stays out of this header.
struct te_expr;

// Compiled single-variable expression. The bound variable is named x.
// Compile once at config load; evaluate many times at simulation time.
// tinyexpr bakes the address of the bound variable into the compiled tree, so
// we keep x on the heap to preserve that pointer across moves.
class Formula
{
public:
    Formula() = default;

    Formula(const Formula&) = delete;
    Formula& operator=(const Formula&) = delete;

    Formula(Formula&& other) noexcept;
    Formula& operator=(Formula&& other) noexcept;

    ~Formula();

    // Parses source and returns a ready-to-evaluate Formula.
    // Throws std::runtime_error with the source and error position on failure.
    static Formula compile(const std::string& source);

    // Evaluates the expression at the given x. Requires a compiled formula.
    double evaluate(double x) const;

    const std::string& getSource() const { return m_source; }
    bool isValid() const { return m_expr != nullptr; }

private:
    std::string m_source;
    std::unique_ptr<double> m_x;
    te_expr* m_expr = nullptr;
};
